C. Password Cracking (C)
若字符串只向一个方向延伸,则一定能通过 \(2n\) 次询问获得结果;可以先向后猜测,当该侧继续添加字符1与0都不符合要求时、说明已经到达字符串末端,继续询问前缀即可。
void solve() {
int n;
cin >> n;
string s = "";
bool flag = 0;
while(s.size() < n) {
if(flag) {
cout << "? 0" << s << endl; // 似乎endl自带清空缓存区的功能
int ok;
cin >> ok;
if(ok) s = "0" + s;
else s = "1" + s;
} else {
cout << "? " << s << '0' << endl;
int ok;
cin >> ok;
if(ok) s += "0";
else {
cout << "? " << s << '1' << endl;
cin >> ok;
if(ok) s += "1";
else flag = 1;
}
}
}
cout << "! " << s << endl;
}
D. Minimize the Difference (D)
似乎挺典的一道题,虽然vp的时候先写E去了没过
由于每次操作只能对前项减1、后项加1,得到的最终序列一定单调不降。用单调栈维护最终序列中元素的大小与数量,后项出现较小数时依次出栈,即可保证复杂度为 \(O(n)\).(有一说一题解的单调栈写得比我好看多了,呜)
void solve() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
int it = 0;
for(int i = 1; i <= n; i++) {
ll sum = a[i];
int cur = 1;
while(it && s[it] >= sum / cur) {
sum += s[it] * cnt[it];
cur += cnt[it];
it--;
}
if(sum % cur) {
s[it + 1] = sum / cur, s[it + 2] = sum / cur + 1;
cnt[it + 1] = cur - (sum % cur), cnt[it + 2] = sum % cur;
it += 2;
} else {
s[it + 1] = sum / cur, cnt[it + 1] = cur;
it++;
}
}
printf("%lld\n", s[it] - s[1]);
}
另有:lzz用二分过的,明天去学学他的写法)
E. Prefix GCD (E)
使用上一场D题的结论可以很快做出这题,每次贪心地将能够最小化gcd的值换到当前位置上,若gcd已经达到最小值,之后元素顺序对答案没有影响。
void solve() {
int n;
scanf("%d", &n);
int g = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
g = __gcd(g, a[i]);
}
sort(a + 1, a + n + 1);
int cur = 0;
for(int i = 1; i <= n; i++) {
int mg = INF, mi;
for(int j = i; j <= n; j++) {
int d = __gcd(cur, a[j]);
if(d < mg) mg = d, mi = j;
}
swap(a[i], a[mi]);
cur = mg;
if(mg == g) break;
}
cur = 0;
ll ans = 0;
for(int i = 1; i <= n; i++) {
cur = __gcd(cur, a[i]);
ans += cur;
}
printf("%lld\n", ans);
}
(虽然上场D题现在还是TLE状态,但至少结论记住了,也算补完了吧)
F1. Game in Tree (Easy Version) (F1)
游戏过程可抽象为:Alice和Bob沿 \(1\) 至 \(u\) 的最短路径相向而行,可以选择在任一时刻进入当前节点下与路径不重合的子树,而子树的最大深度是确定的,可以预处理得到。对Alice而言,若当前最大深度与其经过的长度之和已经大于Bob可以选择的路径最大值,进入子树即为必胜态;对Bob同理。若两人一直选择留在路径上,判断相遇时的步数差即可。
// 这题我的代码好难看。。。
vector <int> v[N];
int dep[N], fa[N];
void pre(int f, int i) {
fa[i] = f, dep[i] = dep[f] + 1;
for(int t : v[i]) {
if(t == f) continue;
pre(i, t);
}
}
int mx[N], sub[N];
bool on[N];
void dfs(int i) {
mx[i] = sub[i] = dep[i];
for(int t : v[i]) {
if(t == fa[i]) continue;
dfs(t);
if(!on[t]) sub[i] = max(sub[i], mx[t]);
mx[i] = max(mx[i], mx[t]);
}
}
int len, p[N], sa[N][20], sb[N][20];
int qa(int l, int r) {
if(l > r) return 0;
int k = __lg(r - l + 1);
return max(sa[l][k], sa[r - (1 << k) + 1][k]);
}
int qb(int l, int r) {
if(l > r) return 0;
int k = __lg(r - l + 1);
return max(sb[l][k], sb[r - (1 << k) + 1][k]);
}
void solve() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
v[i].clear();
}
for(int i = 1; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
pre(0, 1);
int a, b;
scanf("%d%d", &a, &b);
len = 0;
fill(on + 1, on + n + 1, 0);
for(int i = a; i; i = fa[i]) {
p[++len] = i, on[i] = 1;
}
dfs(1);
for(int i = 1; i <= len; i++) {
sa[i][0] = sub[p[i]];
int d = len - i;
if(d < i) sa[i][0] = max(sa[i][0], d + (len - d * 2 + 1) / 2);
sb[i][0] = i + sub[p[i]] - dep[p[i]];
}
for(int k = 1; k <= __lg(len); k++) {
for(int i = 1; i + (1 << k) - 1 <= len; i++) {
sa[i][k] = max(sa[i][k - 1], sa[i + (1 << k - 1)][k - 1]);
sb[i][k] = max(sb[i][k - 1], sb[i + (1 << k - 1)][k - 1]);
}
}
for(int i = 1; i <= len / 2; i++) {
int j = len - i + 1;
if(sa[j][0] > qb(i, j - 1)) {
printf("Alice\n");
return;
}
if(i == j - 1) break;
if(sb[i][0] >= qa(i + 1, j - 1)) {
printf("Bob\n");
return;
}
if(i == j - 2) break;
}
if(len & 1) printf("Alice\n");
else printf("Bob\n");
}
(F2还没补完) 标签:973,cur,int,sum,Codeforces,else,ok,return,Div From: https://www.cnblogs.com/meowqwq/p/18430919