牛客
牛客暑假多校第一场
A
其实就是非常简单的模拟
#include<bits/stdc++.h>using namespace std;#define int long longvoid slove(){ string s; cin >> s; bool t1 = 1; if(s.size() != 8) t1 = 0; string s1 = "aeiou"; for(int i = 0; i < 8; i++){ if(i % 2){ if(s1.find(s[i]) == string::npos){ t1 = 0; } }else{ if(s1.find(s[i]) != string::npos){ t1 = 0; } } } if(!t1){ cout << "Well-Being" << endl; }else{ cout << "Suspected Virus" << endl; }}signed main(){ int t = 1; cin >> t; while(t--){ slove(); }}C
这道题我认为很有意思,其实就是带权并查集 + 连通块的问题: 有一个 的网格,鱼会不断加入。 鱼只能在上下左右移动:
- 遇到大小 自己的鱼,可以吃掉,自己大小
- 遇到更大的鱼,不能通过
- 障碍物也不能通过 题目有两种操作:
- 加入一条新鱼,问它最多能吃多少条鱼
- 对某条已有鱼,允许一开始给它增加体型,问为了吃完整个当前连通块,最少要增加多少
解决思路:
- 首先 操作1 其实就是维护一个连通块的size,但是这里要注意一个问题,就是你左边的方块可能和右边的方块是联通的
- 对于操作二,我们要找到一个关键的性质: , 如果我要往上吃,应该满足的性质,所以如果我要吃完连通块,就相当于 ,所以我们其实可以维护每一个 节点 到 根节点的 dp(吃完需要的最小体积),放到操作二处理,其实如何维护这个 dp,主要就是更新根节点的时候维护每一个连通块向上吃的最小体积,dp 向上传播的过程在find(并查集中实现就可以了)
#include<bits/stdc++.h>using namespace std;
#define int long long
int dx[4] = {1,0,-1,0};int dy[4] = {0,1,0,-1};
void slove(){ int n,m,q; cin >> n >> m >> q; vector<int> dp(n * m + 10 ,0); vector<int> fa(n * m + 10, 0), sz(n * m + 10, 1), dj(n * m + 10, 0); vector<bool> vis(n * m + 10, 0); auto ID = [&](int x, int y) -> int { return (x - 1) * m + y; }; for(int i = 1; i <= n*m; i++){ fa[i] = i; } auto find = [&](int i) -> int { vector<int> r; int t1 = i; while(t1 != fa[t1]){ r.push_back(t1); t1 = fa[t1]; } int root = t1; int ed = r.size() - 1; int cur = 0; for(int k = ed; k >= 0; k--){ int id = r[k]; dp[id] = max(cur, dp[id]); cur = dp[id]; fa[id] = root; } return root; }; int l = 0; for(int i = 1; i <= q; i++){ int op; cin >> op; if(op == 1){ int x, y, v; cin >> x >> y >> v; x ^= l; y ^= l; dj[ID(x, y)] = v; int root1 = ID(x, y); vis[root1] = 1; vector<int> ro; for(int i = 0; i < 4; i++){ int x1 = x + dx[i], y1 = y + dy[i]; if(x1 < 1 || x1 > n || y1 < 1 || y1 > m) continue; int id1 = ID(x1,y1); if(!vis[id1]) continue; int r = find(id1); bool flag = 1; for(auto tt : ro){ if(tt == r) flag = 0; } if(flag) ro.push_back(r); } for(auto x : ro){ dp[x] = max(0ll, v - sz[x] + 1); fa[x] = root1; sz[root1] += sz[x]; } l = sz[root1] - 1; cout << sz[root1] - 1 << endl; }else if(op == 2){ int x, y; cin >> x >> y; x ^= l; y ^= l; int root1 = ID(x, y); find(root1); l = max(0ll, dp[root1] - dj[root1]); cout << max(0ll, dp[root1] - dj[root1]) << endl; } }}
signed main(){ int t = 1; // cin >> t; while(t--){ slove(); }}E
非常简单的一道题目,看规律都能看出来
#include<bits/stdc++.h>using namespace std;
#define int long long
void slove(){ int n; cin >> n; vector<int> a(n + 1, 0); for(int i = 1; i <= n; i++){ cin >> a[i]; } int ans = 0; for(int i = 1; i <= n; i++){ ans += (a[i] * i) - (a[i] * (n - i + 1)); } cout << ans << endl;}
signed main(){ int t = 1; // cin >> t; while(t--){ slove(); }}F
解法:作为构造题,我们的想法不能过于复杂,从 公式中
的形式,为了保证 这个 f(P) 不变,所以根据这种形式,我们能不能从循环的形式去刻画这个问题,所以我们要去验证这个 循环是不是 f(P) 是否不变
#include<bits/stdc++.h>using namespace std;
#define int long long
void slove(){ int n, k, x; cin >> n >> k >> x; vector<int> a(n, 0); for(int i = 0; i < n; i++){ cin >> a[i]; } int pos = 0; for(int i = 0; i < n; i++){ if(a[i] == x){ pos = i; break; } } int t1 = (k - pos + n) % n; vector<int> ans(n); for(int i = 0; i < n; i++){ ans[(i + t1) % n] = a[i]; } for(auto &x : ans) cout << x << " "; cout << endl;
}
signed main(){ int t = 1; // cin >> t; while(t--){ slove(); }}G
考虑这个 误差 去考虑,发现计算,就是 节点直接距离看成1,可以用一个正方向包裹 100 个以上,所以我们在高度为一的上下两个平面去构建两个正方形就可以
#include<bits/stdc++.h>using namespace std;
#define int long long
void slove(){ // cout << sqrt(1.01 * 1.01-1) / 0.0101 << endl; int m; cin >> m; int t1 = m; cout << 2 * m << endl; for(int i = 0; i < 10; i++){ for(int j = 0; j < 10; j++){ cout << (i) * 0.0101 << " " << j * 0.0101 << " " << 0 << endl; t1 --; if(t1 == 0) break; } if(t1 == 0) break; } for(int i = 0; i < 10; i++){ for(int j = 0; j < 10; j++){ cout << (i) * 0.0101 << " " << j * 0.0101 << " " << 1 << endl; m --; if(m == 0) break; } if(m == 0) break; } // cout << "------------" << endl;;}
signed main(){ int t = 1; cin >> t; while(t--){ slove(); }}H
这道题目如果赛时的话只能通过打表的形式去找规律了,不然很难想到 只要模拟前 100 轮,后面每轮的变化量差不多,其实就是 打表观察差分是否收敛的现象,然后再去模拟这个过程:
- 首先当前步骤是 依靠后面步骤的最高收益,所以可以采用 DP,从后面的步骤开始往前面的步骤模拟,然后去模拟 A,B 的出牌选择 就可以了
#include<bits/stdc++.h>using namespace std;
#define int long longvector<vector<double>> dp(101, vector<double>(101, 0.00));map<array<int,3>,int> id;vector<array<int,3>> hand;void slove(){ int k; cin >> k; string s1,s2; cin >> s1 >> s2; array<int,3> t1 = {0,0,0}; array<int,3> t2 = {0,0,0}; for(int i = 0; i < 3; i++){ if(s1[i] == 'R') t1[0] ++; else if(s1[i] == 'S') t1[1] ++; else if(s1[i] == 'P') t1[2] ++; } for(int i = 0; i < 3; i++){ if(s2[i] == 'R') t2[0] ++; else if(s2[i] == 'S') t2[1] ++; else if(s2[i] == 'P') t2[2] ++; } int ID1 = id[t1]; int ID2 = id[t2]; int state = ID1 * 10 + ID2; cout << fixed << setprecision(10); // cout << dp[k][state] << endl; double ans = 0; if(k <= 100){ cout << dp[k][state] << endl; }else{ double d = dp[100][state] - dp[99][state]; cout << dp[100][state] + (k - 100) * d << endl; }}
void init(){
int id1 = 0; for(int i = 0; i <= 3; i++){ for(int j = 0; j + i <= 3; j++){ int k = 3 - i - j; array<int,3> temp = {i, j, k}; id[temp] = id1 ++; hand.push_back(temp); } } auto score = [&](int x1, int y1) -> double { if((x1 == 0 && y1 == 1) || (x1 == 1 && y1 == 2) || (x1 == 2 && y1 == 0)){ return 3; }else if((x1 == y1)){ return 1; }else return 0; };
for(int T = 1; T <= 100; T++){ // A 牌的种类 for(int i = 0; i < 10; i++){ // B 牌的种类 for(int j = 0; j < 10; j++){ int state = i * 10 + j; // A 打哪张牌 double best = 0; for(int i1 = 0; i1 < 3; i1++){ if(hand[i][i1] == 0) continue; // B 打哪张牌 double worst = (double)1e9; for(int j1 = 0; j1 < 3; j1++){ auto tt2 = hand[j]; auto tt1 = hand[i]; if(tt2[j1] == 0) continue; tt2[j1] --; tt1[i1] --; double cur = score(i1, j1);
// 补牌环节 double s1 = 0; for(int add1 = 0; add1 < 3; add1 ++){ for(int add2 = 0; add2 < 3; add2++){ auto temp1 = tt1; auto temp2 = tt2; temp1[add1] ++; temp2[add2] ++; int p1 = id[temp1]; int p2 = id[temp2]; int ID = p1 * 10 + p2; s1 += dp[T-1][ID]; } } cur += (s1 / (9.0)); worst = min(worst, cur); } best = max(best, worst); } dp[T][state] = best; } } }}
signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); init(); int t = 1; cin >> t; while(t--){ slove(); }}

评论
欢迎留下你的想法,友善交流。
评论区暂时加载失败,请稍后刷新重试。