牛客多校2023 第二场
依旧是随便写点东西(
D
根据sample input猜测从后往前贪心即可
#include <bits/stdc++.h> using namespace std; int N,M; int T; bool vis[5005]; int a[2005][2005]; int main(){ cin >> T; while (T--){ int N,M,K; cin >> N >> M >> K; for (int i = 1 ; i <=N ; i ++) for (int j = 1 ; j <= M ; j ++) cin >> a[i][j]; vector<int> nw; memset(vis,false,sizeof(vis)); for (int v = K ; v ; v --){ int i = v % N; if (i == 0) i = N; int pos = -1; for (int j = 1 ; j <= M ; j ++){ if (!vis[j]){ if (pos == -1 || a[i][j] >= a[i][pos]) pos = j; } } if (pos != -1){ nw.push_back(pos); vis[pos] = true; } } sort(nw.begin(),nw.end()); for (auto v : nw) cout << v << " "; cout << endl; } return 0; }
E
签到题.jpg
#include <bits/stdc++.h> #define ll long long using namespace std; long long T,x; int main(){ cin >> T; while (T--){ cin >> x; ll t = 1; bool flag = false; for (int i = 1 ; i <= 18 ; i ++,t*=10){ ll aa = x*t; if (aa > 1e18) break; ll sq = ceil(sqrt(aa)); if (floor(sq * sq / t) == x){ flag = true; cout << sq << '\n'; break; } } if (!flag) cout << "-1\n"; } return 0; }
F
先把问题转化成一个三维路径问题,不能碰到走过的点
然后不难发现,其实一个必败态非常难构造,一个点非常难被困
所以大胆猜测,所有的$n^3$个点都会被遍历到
考虑两个人的行动方式
$(r,g,b) =>(r+1,g,b)$等
会发现$r+g+b$的奇偶性对于先/后手来说都不变
于是其实只需要统计$r+g+b$为奇/偶的时候谁是那个多$1$的即可
即$n^3 % 2 == (r+g+b)%2$
#include<bits/stdc++.h> using namespace std; int T; long long t; int main(){ cin >> T; while (T--){ int N,r,g,b; cin >> N >> r >> g >> b; if(N&1 == (r+g+b) %2){ cout << "Bob\n"; } else cout << "Alice\n"; } return 0; }
G
我想的是个$PAM$
但是学弟似乎写了个结论+魔改马拉车?
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int N = 1000010; char rev[256]; char c[N], s[N]; int n, cnt; int mid, mr; bool jg(char a, char b){ if(b == rev[a]) return true; return false; } void init(){ for(int i = 0; i < 256; i ++) rev[i] = 1; rev['b'] = 'q'; rev['d'] = 'p'; rev['p'] = 'd'; rev['q'] = 'b'; rev['n'] = 'u'; rev['u'] = 'n'; rev['o'] = 'o'; rev['s'] = 's'; rev['x'] = 'x'; rev['z'] = 'z'; rev['#'] = '#'; } void build(){ s[++ cnt] = '~', s[++ cnt] = '#'; for(int i = 1; i <= n; i++){ s[++ cnt] = c[i]; s[++ cnt] = '#'; } s[++ cnt] = '!'; s[cnt + 1] = '\0'; } void solve(){ scanf("%s", c + 1); n = strlen(c + 1); mid = mr = cnt = 0; build(); int start = 2; vector<int> p(cnt + 10); for(int i = 2; i < cnt; i ++){ if(i <= mr) p[i] = min(p[mid * 2 - i], mr - i + 1); else p[i] = -1; while(jg(s[i - p[i] - 1], s[i + p[i] + 1])) p[i] ++; if(i + p[i] - 1 > mr) { mr = i + p[i] - 1; mid = i; } if(p[i] > 0 && i - p[i] <= start) { s[i + p[i] - 1] = '~'; start = i + p[i]; i = i + p[i] - 1; } } if(start == cnt - 1) puts("Yes"); else puts("No"); } int main(){ // ios::sync_with_stdio(false); // cin.tie(nullptr); init(); int T; cin >> T; while(T --){ solve(); } return 0; }
H
两个操作很复杂,考虑怎么统一成一个
根据计算机组成原理的知识:
假设一个数的补码为$x$
反码为$~x$
$~x$+$x$ = $0xffffffff$
而补码下$0xffffffff$ = $-1$
所以x+~x=-1
==>~x=-x-1
统一成功.jpg(一点小小的408震撼)
然后就可以线段树维护矩阵来优化啦(
但是可以有个更简洁的写法
首先我们可以明确:
答案的表达形式一定是$(-1)^k * x + b$
其中$k$是$[l,r]$中$A$的数量(因为要取这么多次反)
然后考虑$b$怎么处理
会考虑前缀
假设$b_{l-1}$和$b_r$分别表示算到$l-1$和$r$的时候的$b$
那么对于$b_{l-1}$来说,它后面本来要经历$k$次翻转,然后贡献到$b_r$中
这里我们需要扔掉$b_{l-1}$的贡献,所以如果$k$为奇数的话
因为它后面经历了奇数次翻转,所以加入答案的贡献是$-b_{l-1}$
所以我们算的时候要把这部分贡献补回来,所以是$+b_{l-1}$
偶数亦然
然后就结束啦(
#include <bits/stdc++.h> #define ll long long #define int long long using namespace std; int N,Q; const int mx = 2e5+10; string ss; int Sum[mx]; int Pre[mx]; string x; signed main(){ cin >> N >> Q; cin >> ss; int Len = ss.length(); for (int i = 1 ; i <= Len ; i ++){ if (ss[i-1] == 'A'){ Sum[i] = Sum[i-1] * (-1) - 1; Pre[i] = Pre[i-1] + 1; } else { Sum[i] = Sum[i-1] + 1; Pre[i] = Pre[i-1]; } } int lasans = 0; while (Q--){ int l,r; cin >> l >> r; int L,R; L = min(((lasans^l)%N)+1,(((lasans^r))%N)+1); R = max(((lasans^l)%N)+1,(((lasans^r))%N)+1); l = L , r = R; int Cnt = Pre[r] - Pre[l-1]; int Sign = 0; if (Cnt & 1ll) Sign = 1; else Sign = -1; int Sign1 = 0; if (Cnt & 1) Sign1 = -1; else Sign1 = 1; cin >> x; int Len = x.length(); long long xx = 0; for (int i = 0 ; i < Len ; i ++) xx = xx*2ll + x[i] - '0'; ll P = (1ll<<(Len)); ll Sum1 = Sign * Sum[l-1] + Sum[r]; long long ans = ((Sign1 * xx)%P + Sum1%P)%P; if (ans < 0) ans = (ans + P)%P; string ss1 = ""; lasans = ans; for (int i = 0 ; i < Len ; i ++){ if (ans & (1ll<<i)) ss1 = '1' + ss1; else ss1 = '0' + ss1; } cout << ss1 << '\n'; } return 0; }
干啥啥不行