Codeforces Round #651 (Div. 2)
感觉自己无可救药了。
A题:找到小于等于n的两个不同的数的gcd最大是多少,显然是floort(n/2)。设这两数是a * gcd, b * gcd然后gcd(a,b) = 1,那么gcd要尽量大,不妨就a = 1,b = 2。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <map> 7 #include <cmath> 8 #include <queue> 9 #include <set> 10 #define rep(i,j,k) for(int i = j; i <= k; i++) 11 #define dow(i,j,k) for(int i = j; i >= k; i--) 12 #define fi first 13 #define se second 14 using namespace std; 15 16 17 typedef long long ll; 18 typedef pair<int,int> pi; 19 20 using namespace std; 21 int t; 22 int main() { 23 cin >> t; 24 while (t--) { 25 int n; 26 cin >> n; 27 n = n / 2; 28 cout << n << endl; 29 } 30 }
B题:给定2n个数,从中去掉两个数。剩下的数配成n - 1对,然后要求这些对的和的最大gcd大于1。大于1,那就gcd等于2就好了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> #include <queue> #include <set> #define rep(i,j,k) for(int i = j; i <= k; i++) #define dow(i,j,k) for(int i = j; i >= k; i--) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pi; const int N = 1005; int n, cnt[2], t; struct node{ int val, i; }a[N*2]; bool cmp(node x,node y) { return (x.val & 1) < (y.val & 1); } void solve() { scanf("%d", &n); cnt[0] = cnt[1] = 0; rep(i,1, n * 2) scanf("%d", &a[i].val), a[i].i = i,cnt[a[i].val & 1]++; sort(a + 1, a + n * 2 + 1, cmp); if (cnt[1] & 1) { for(int i = 2; i < n * 2; i+=2) { printf("%d %d\n", a[i].i, a[i+1].i); } return; } for(int i = 1; i < n * 2 - 1; i+=2) { printf("%d %d\n", a[i].i, a[i+1].i); } return ; } int main() { scanf("%d", &t); while(t--) { solve(); } }
C题:game题,给一个数n,每次可以减1,如果有奇数因子可以除以奇数因子(包括本身),轮流操作,到1就输了。不知道有什么好做法,写了一堆if。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> #include <queue> #include <set> #define rep(i,j,k) for(int i = j; i <= k; i++) #define dow(i,j,k) for(int i = j; i >= k; i--) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pi; const int N = 1005; int dp[N]; bool isprime(int x) { for(int i = 2; i * i <= x; i++) { if (x % i == 0) return 0; } return 1; } int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); if (n == 1) { printf("FastestFinger\n"); } else if (n == 2) { puts("Ashishgup"); } else if (n & 1) { puts("Ashishgup"); } else{ int cnt = 0; while (n % 2 ==0) cnt++, n /= 2; if (n == 1) { puts("FastestFinger"); } else if (cnt == 1) { if (isprime(n)) puts("FastestFinger"); else puts("Ashishgup"); } else puts("Ashishgup"); } } }
D题:从一个数组里找一个长度为k的子序列,子序列的代价是,子序列的奇数位和偶数位中的最大值中的较小的值。猜测二分贪心是个好做法,然后过了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> #include <queue> #include <set> #define rep(i,j,k) for(int i = j; i <= k; i++) #define dow(i,j,k) for(int i = j; i >= k; i--) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pi; const int N = 200005; int n, k; int a[N]; bool solve(int x) { int f = 1; int cnt = 0; rep(i,1,n) { if (cnt % 2 == 0) cnt++; else if (a[i] <= x) cnt++; } if (cnt >= k) return 1; cnt = 0; rep(i,1,n) { if (cnt & 1) cnt++; else if(a[i] <= x) cnt++; } if (cnt >= k) return 1; return 0; } int main() { scanf("%d %d", &n, &k); rep(i,1,n) scanf("%d", &a[i]); int l = 1, r = 1e9; while (l < r) { //cerr << l << " " << r << endl; int mid = (l + r) >> 1; if (solve(mid)) r = mid; else l = mid + 1; } printf("%d\n", l); }
E题:给你两个长度相等的01串,每次可以选择第一个串中的一个子序列,对子序列进行循环右移(不太会简单描述这个操作),然后问最少多少次可以让两个串一样,或者无法实现。
如果两个串01数量不想等就不行,否则就可以。而且我们直接忽视掉已经匹配的位置。然后第一个串就是一堆01,现在要让0到1的位置,1到0的位置。最直接的方法直接配对然后全部循环右移即可。
01可以一次变10。发现010101可以一次变101010也就是说交替的01一次做能减少我们的操作次数。然后就找一下每个0能不能找到交替的1。然后就瞎写了写就莫名其妙过了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> #include <queue> #include <set> #define rep(i,j,k) for(int i = j; i <= k; i++) #define dow(i,j,k) for(int i = j; i >= k; i--) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pi; const int N = 1e6 + 100; int n; char s[N], t[N]; int a[N]; int tot; int ans; //int lens, lent int cnts, cntt; int main() { scanf("%d", &n); scanf("%s", s + 1); scanf("%s", t + 1); rep(i,1,n) if (s[i] == '1') cnts++; rep(i,1,n) if (t[i] == '1') cntt++; if (cnts != cntt) { puts("-1"); return 0; } // int tot = 0; rep(i,1,n) { if (s[i] == t[i]) continue; a[++tot] = s[i] - '0'; } ans = tot; //cerr << tot << "!!!" << endl; //rep(i,1,tot) cerr << a[i] << " "; cerr << endl; int j = 1; rep(i,1,tot) { if (a[i] != 0) continue; j = max(i, j); while (a[j] == 0 && j <= tot) j++; if (j <= tot) { ans--; j++; } } j = tot; dow(i,tot,1) { if (a[i] != 0) continue; j = min(i, j); while (a[j] == 0 && j >= 1) j--; if (j >= 1) { ans --; j--; } } printf("%d\n", ans); }
f:一个树上,有两个hidden的点。每次询问一个点集,返回到两点距离之和最小的一个点和到两点的距离之和。11次之内搞出来。1000个点
并不会做。然后就等第二天看题解了。
询问所有点,找出两点间路径上的一个点,然后二分,询问深度为mid的所有点,如果说返回的距离大于第一次询问的点,深度就过深了,然后10次内就能搞出某个hidden的点,然后就知道另一个点的深度再询问一次就好。
如果两点距离为d,那么至少有一个点深度是ceil(d / 2),那么就相当于使二分的边界少了一半,11次就能搞定。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <map> #include <cmath> #include <queue> #include <set> #define rep(i,j,k) for(int i = j; i <= k; i++) #define dow(i,j,k) for(int i = j; i >= k; i--) #define fi first #define se second using namespace std; typedef long long ll; typedef pair<int,int> pi; const int N = 1005; struct edge{ int to,next; }e[N << 1]; int n, cnt, h[N]; int dep[N]; int rt, d; pi ans[N]; int vis[N]; void add(int u,int v) { e[++cnt] = (edge) {v, h[u]}; h[u] = cnt; } void dfs(int x) { for (int i = h[x]; i; i = e[i].next) { int v = e[i].to; if (!dep[v] && v != rt) dep[v] = dep[x] + 1, dfs(v); } } void dfs2(int x, vector<int> &cnt, int dis) { vis[x] = 1; if(dis == d) { cnt.push_back(x); return ; } for (int i = h[x]; i; i = e[i].next) { int v = e[i].to; if (!vis[v]) dfs2(v, cnt, dis + 1); } } void solve() { cnt = 0; int x, y; int a = 0, b = 0; memset(h, 0, sizeof(h)); memset(dep, 0, sizeof(dep)); memset(ans, 0, sizeof(ans)); scanf("%d", &n); rep(i,1,n-1) { int u, v; scanf("%d %d", &u, &v); add(u, v); add(v, u); } printf("? %d ", n); rep(i,1,n) printf("%d ", i); puts(""); fflush(stdout); scanf("%d %d", &rt, &d); int l = (d + 1) / 2, r = d; dfs(rt); ans[0] = make_pair(rt, d); while(1) { int mid = (l + r + 1) >> 1; if (!ans[mid].fi) { vector<int> temp; rep(i,1,n) if (dep[i] == mid) temp.push_back(i); int cnt = temp.size(); if (cnt == 0) { r = mid - 1; continue; } printf("? %d ", cnt); rep(i,0,cnt-1) printf("%d ", temp[i]); puts(""); fflush(stdout); scanf("%d %d", &x, &y); ans[mid] = make_pair(x, y); } if (ans[mid].se > d) r = mid - 1; else l = mid; if (l == r && l == mid) {a = ans[l].fi; break;} } vector<int> temp; memset(vis, 0, sizeof(vis)); dfs2(a, temp, 0); int cnt = temp.size(); if (cnt == 1) b = temp[0]; else { printf("? %d ", cnt); rep(i,0, cnt - 1) printf("%d ", temp[i]); puts(""); fflush(stdout); scanf("%d %d", &x, &y); b = x; } printf("! %d %d\n", a, b); string s; fflush(stdout); cin >> s; } int main() { int t; scanf("%d", &t); while (t--) { solve(); } }
感觉自己明明d、e都不会做就是瞎蒙对的……
然后交互题尽量应该把交互的过程封装一下。

浙公网安备 33010602011771号