《Codeforces Round #669 (Div. 2)》
A:又又又读错题了~
如果1和0的个数一样,就删完1.
如果0的个数多,也删完0.
然后1的个数多,那就留下偶数个1即可
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<LL,int> pii; const int N = 1e3+5; const int M = 1e6+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; int a[N]; int main() { int ca;ca = read(); while(ca--) { int n;n = read(); int cnt0 = 0,cnt1 = 0; for(rg int i = 1;i <= n;++i) { a[i] = read(); if(a[i] == 1) cnt1++; else cnt0++; } if(cnt1 > cnt0) { if(cnt1%2 == 0) { printf("%d\n",cnt1); for(rg int i = 1;i <= n;++i) if(a[i] == 1) printf("1 "); } else { printf("%d\n",cnt1-1); int f = 0; for(rg int i = 1;i <= n;++i) { if(a[i] == 1) { if(f) printf("1 "); f = 1; } } } } else if(cnt0 > cnt1) { printf("%d\n",cnt0); for(rg int i = 1;i <= n;++i) if(a[i] == 0) printf("0 "); } else { printf("%d\n",cnt0); for(rg int i = 1;i <= n;++i) if(a[i] == 0) printf("0 "); } printf("\n"); } // system("pause"); }
B:首先最大的肯定放最前面。
然后就暴力找一下和前面的gcd取gcd更大的点,然后放入。
如果出现多个点gcd都能最大,可以任意放哪个,因为c只是他们的gcd,且后面找位置都是用gcd去更新,所以只有gcd有影响
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e3+5; const int M = 2e5+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; int a[N],b[N],vis[N]; int main() { int ca;ca = read(); while(ca--) { int n;n = read(); for(rg int i = 1;i <= n;++i) a[i] = read(); memset(vis,0,sizeof(vis)); sort(a+1,a+n+1); b[1] = a[n],vis[n] = 1; int gcd = b[1]; for(rg int i = 2;i <= n;++i) { int mx = -1,pos; for(rg int j = n;j >= 1;--j) { if(!vis[j] && __gcd(gcd,a[j]) > mx) { mx = __gcd(gcd,a[j]); pos = j; } } gcd = mx,b[i] = a[pos],vis[pos] = 1; } for(rg int i = 1;i <= n;++i) printf("%d%c",b[i],i == n ? '\n' : ' '); } }
C:很有意思的一个交互题~
有这样一个结论:
小的数 mod 大的数 一定 > 大的数 mod 小的数。
这也非常好证明。
设a = 小的数,b = 大的数.
a mod b = a。b mod a = [0,a)。
因为我们可以去询问最大2*n次。
然后我们可以两次询问a mod b 和 b mod a。
就能把小的那个数确定下来。
然后找n次即可。注意最后的留下的数是n且不会再判断
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e4+5; const int M = 2e5+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; int a[N]; int main() { int n;n = read(); int st = 1; for(rg int i = 2;i <= n;++i) { printf("? %d %d\n",st,i); fflush(stdout); int mod1;mod1 = read();//st%i printf("? %d %d\n",i,st); fflush(stdout); int mod2;mod2 = read();//i%st if(mod1 < mod2) { a[i] = mod2; } else { a[st] = mod1; st = i; } } a[st] = n; printf("! "); for(rg int i = 1;i <= n;++i) printf("%d%c",a[i],i == n ? '\n' : ' '); fflush(stdout); }
D:其实这个题目没有那么难(但还是挺难的
首先显然是一个单调队列或者单调栈优化的dp。
主要是怎么去优化,这里一开始想单调队列想了好久都没想清楚。
Solution:我们可以去维护一个单调递减和单调递增的栈。
对于单调递增栈来说。
因为是单调递增,所以当a[i] < a[top]时。
我们就可以边退栈变更新。因为每一次退栈时都满足之前退的元素 > a[i]和a[top],那么显然就能更新出。
注意我们退完后的栈顶,刚好也是满足之前退栈的元素全都 > a[i]和a[top]的。所以对栈顶再求一次最小的dp。
那么也可以发现,我们中间退栈的时候需要保持严格的大于才能退栈。
那么也就会导致我们栈中可能会有连续重复的元素,这时显然要无法满足更新条件,因为中间都相同的话也不满足条件。
所以我们要对相同的也进行退栈。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 3e5+5; const int M = 2e5+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; int a[N],dp[N],S1[N],S2[N];//递减栈,递增栈 int main() { int n;n = read(); for(rg int i = 1;i <= n;++i) a[i] = read(); memset(dp,0x3f,sizeof(dp)); dp[1] = 0; int top1 = 0,top2 = 0; S1[++top1] = 1,S2[++top2] = 1; for(rg int i = 2;i <= n;++i) { dp[i] = min(dp[i],dp[i-1]+1); while(top1 != 0 && a[i] > a[S1[top1]]) dp[i] = min(dp[i],dp[S1[top1--]]+1); if(top1 != 0) dp[i] = min(dp[i],dp[S1[top1]]+1); while(top1 != 0 && a[S1[top1]] == a[i]) top1--; S1[++top1] = i; while(top2 != 0 && a[i] < a[S2[top2]]) dp[i] = min(dp[i],dp[S2[top2--]]+1); if(top2 != 0) dp[i] = min(dp[i],dp[S2[top2]]+1); while(top2 != 0 && a[S2[top2]] == a[i]) top2--; S2[++top2] = i; } //for(rg int i = 1;i <= n;++i) printf("dp[%d] is %d\n",i,dp[i]); printf("%d\n",dp[n]); }
E:逮捕~