Gym 100851 题解
A: Adjustment Office
题意:在一个n*n的矩阵,每个格子的的价值为 (x+y), 现在有操作取一行的值,或者一列的值之后输出这个和, 并且把这些格子上的值归0。
题解:模拟, 分成xy轴就好了。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("adjustment.in","r",stdin); freopen("adjustment.out","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1e6 + 100; LL sumx, sumy; int cntx, cnty; int visx[N], visy[N]; char op[5]; int p; int main(){ Fopen; int n, q; scanf("%d%d", &n, &q); sumx = sumy = (1ll+n)*n / 2; cntx = cnty = n; while(q--){ scanf("%s%d", op, &p); if(op[0] == 'R'){ if(visx[p]) puts("0"); else{ visx[p] = 1; LL ans = 1ll * cnty * p + sumy; sumx -= p; --cntx; printf("%lld\n", ans); } } else { if(visy[p]) puts("0"); else{ visy[p] = 1; LL ans = 1ll * cntx * p + sumx; sumy -= p; --cnty; printf("%lld\n", ans); } } } return 0; }
D:题解传送门
E:Easy Problemset
题意:有n组题目,每组题目有pi个题目,然后每个题目有一个[0, 49]的难度, 现在轮着选这些题, 当入选题目的总难度小于等于当天题目的时候,就把这个题目加入入选题目, 如果一组题目用完了就用50的题目去填充,当选完了所有题目之后还没有满足条件,就用难度50的题目填充剩下的。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("easy.in","r",stdin); freopen("easy.out","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1e5 + 100; int p[13][15]; int a[100]; int main(){ Fopen; int n, k; scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++i){ scanf("%d", &a[i]); for(int j = 1; j <= a[i]; ++j) scanf("%d", &p[i][j]); for(int j = a[i]+1; j < 15; ++j) p[i][j] = 50; } int sum = 0; for(int j = 1; j < 15; ++j){ for(int i = 1; i <= n; ++i){ if(sum <= p[i][j]){ sum += p[i][j]; --k; if(k == 0){ printf("%d\n", sum); return 0; } } } } sum += 50 * k; printf("%d\n", sum); return 0; }
F:Froggy Ford
题意:从图的最左边跑到最右边,只能在点(河岸),现在可以新增一个点,问你从最左边跳到最右边,最长跳远最小可以是多少。
题解:我们从左边跑一遍n^2的最短路,然后从右边跑一遍最短路,然后再枚举2个点找最优解就好了。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("froggy.in","r",stdin); freopen("froggy.out","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1100; double e[N][N]; pll p[N]; int w, n; inline double cal(pll & p1, pll & p2){ return sqrt(pow(p1.fi-p2.fi, 2) + pow(p1.se-p2.se,2)); } double dis[2][N]; int vis[N]; void dijkstra(int st,int op){ memset(vis, 0, sizeof(vis)); for(int i = 0; i <= n + 1; ++i) dis[op][i] = e[st][i]; dis[op][st] = 0; vis[st] = 1; while(true){ double min1 = INF; int z = -1; for(int j = 0; j <= n+1; j++) if(!vis[j] && min1 > dis[op][j]) z = j, min1 = dis[op][j]; if(z == -1) break; vis[z] = 1; for(int j = 0; j <= n; ++j){ dis[op][j] = min(dis[op][j], max(e[z][j], dis[op][z])); } } } int main(){ Fopen; scanf("%d%d", &w, &n); for(int i = 1; i <= n; ++i) scanf("%d%d", &p[i].fi, &p[i].se); for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j){ e[i][j] = cal(p[i], p[j]); } for(int i = 1; i <= n; ++i){ e[i][0] = e[0][i] = p[i].fi; e[i][n+1] = e[n+1][i] = w - p[i].fi; } e[n+1][0] = e[0][n+1] = w; dijkstra(0,0); dijkstra(n+1,1); int p1, p2; double llen = INF; for(int i = 0; i <= n + 1; ++i){ for(int j = 0; j <= n+1; ++j){ double tmp = max3(dis[0][i], dis[1][j], e[i][j]/2.0); if(tmp < llen){ llen = tmp; p1 = i, p2 = j; } } } int ansx, ansy; if(p1 > p2) swap(p1, p2); if(p1 == 0){ ansx = p[p2].fi; ansy = p[p2].se*2; } else if(p2 == n+1){ ansx = p[p1].fi + w; ansy = p[p1].se * 2; } else { ansx = p[p1].fi + p[p2].fi; ansy = p[p1].se + p[p2].se; } if(ansx&1) printf("%d.5 ", ansx/2); else printf("%d ", ansx/2); if(ansy&1) printf("%d.5", ansy/2); else printf("%d", ansy/2); return 0; }
G:Generators
题意:有n个生成序列,现在要你在这n个生成序列每个都找到一个值相加,要求和在不能被k整除的情况下最大。
题解:暴力跑出循环节,找到每个序列的最大值和次大值,最大值和次大值的差不能被k整除,然后把每个序列的最大值相加, 然后如果被k整除,就找一个次小值去替换。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("generators.in","r",stdin); freopen("generators.out","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 11000; int vis[1005]; int A[N]; int p[N][2], v[N][2]; int main(){ Fopen; int n, k, a, b, c, x, m; scanf("%d%d", &n, &k); int sum = 0; for(int i = 1; i <= n; ++i){ scanf("%d%d%d%d", &x, &a, &b, &c); m = 0; while(!vis[x]){ A[++m] = x; vis[x] = 1; x = (a*x + b) % c; } for(int j = 1; j <= m; ++j){ vis[A[j]] = 0; if(v[i][0] <= A[j]){ v[i][0] = A[j]; p[i][0] = j; } } sum += v[i][0]; for(int j = 1; j <= m; ++j){ if(v[i][0] == A[j]) continue; if((v[i][0]-A[j])%k != 0 && v[i][1] <= A[j]){ v[i][1] = A[j]; p[i][1] = j; } } } if(sum % k == 0){ int tmp = 0, pos, val = 0; for(int i = 1; i <= n; ++i){ if(p[i][1] == 0) continue; tmp = sum - v[i][0] + v[i][1]; if(tmp > val){ val = tmp; pos = i; } } if(val != 0){ sum = val; p[pos][0] = p[pos][1]; } } if(sum%k == 0) puts("-1"); else { printf("%d\n", sum); for(int i = 1; i <= n; ++i) printf("%d ", p[i][0]-1); } return 0; }
J:Jump 交互题
题意:现在有一个长度为偶的01序列,然后要求你每次输出一个序列,如果这个输出序列的和原序列的相同的位置的个数是 n 或者 n/2 的话会输出这个值否者输出0。
题解:先rand找到一个n/2的,然后就假设第一位值正确的,然后枚举每个位置的变化。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1e5 + 100; char s[N]; char ans1[N], ans2[N]; int f = 0, n, t; void boom(){ for(int i = 0; i < n; ++i) s[i] = '0' + ((rand()%2)); } int main(){ srand(19990629); scanf("%d", &n); s[n] = '\0'; while(1){ boom(); puts(s); cout << flush; scanf("%d", &f); if(f == n) return 0; if(f == n/2) break; } if(f == n/2){ ans1[0] = s[0]; ans2[0] = '0' + '1' - s[0]; s[0] = '0' + '1' - s[0]; for(int i = 1, t; i < n; ++i){ s[i] = '0' + '1' - s[i]; printf("%s\n", s); cout << flush; scanf("%d", &t); if(t == n/2) { ans1[i] = s[i]; ans2[i] = '0' + '1' - s[i]; } else { ans1[i] = '0' + '1' - s[i]; ans2[i] = s[i]; } s[i] = '0' + '1' - s[i]; } ans1[n] = '\0'; ans2[n] = '\0'; printf("%s\n", ans1); cout << flush; scanf("%d", &t); if(t != n){ printf("%s\n", ans2); cout << flush; } } return 0; }
K:King’s Inspection
题意:有一幅图 n个点的图,m个单向边, 问能不能从1号点出发,然后绕一圈,经过其他的所有的点一次,然后会到一号点。
题解:因为最多是 n+20条边,我们先判断一下有没有 入度为0 或者 出度为0有就是非法的。
20个多的边 如果都走一遍 也就是 2^20次方 ≈ 1e6, 但是 我们如果遍历其他的链, 那么要1e6 * 1e5 就不行了。
所以我们把这些单链都缩点,缩成一条边,这样在图合法的前提下,我们的图就会很小,就可以爆搜了。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("king.in","r",stdin); freopen("king.out","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1e5 + 100; vector<int> e[N]; vector<pll> vc[N]; int in[N], out[N], ok[N], vis[N]; int nt[N]; int sta[N]; int n, m, u, v; void P(int k){ for(int i = 1; i <= k; ++i){ printf("%d ", sta[i]); if(ok[sta[i]]){ int x = nt[sta[i]]; while(x){ printf("%d ", x); x = nt[x]; } } } printf("1"); } void dfs(int u, int k, int num){ sta[k] = u; vis[u] = 1; for(int i = 0; i < vc[u].size(); ++i){ int v = vc[u][i].fi, ct = vc[u][i].se; if(vis[v]){ if(v == 1 && num + ct == n){ P(k); exit(0); } continue; } vis[v] = 1; dfs(v, k+1, num+1+ct); vis[v] = 0; } } int main(){ Fopen; scanf("%d%d", &n, &m); for(int i = 1; i <= m; ++i){ scanf("%d%d", &u, &v); in[v]++, out[u]++; e[u].pb(v); } for(int i = 1; i <= n; ++i){ if(in[i] < 1 || out[i] < 1) { puts("There is no route, Karl!"); return 0; } ok[i] = (in[i] == 1 && out[i] == 1); } ok[1] = 0; for(int i = 1; i <= n; ++i){ if(vis[i]) continue; if(ok[i]){ int to = e[i][0], ct = 0, now = i; vis[i] = 1; while(ok[to]){ if(vis[to]){ if(to == i) break; nt[now] = to; ct += vc[to][0].se + 1; to = vc[to][0].fi; } else { ct++; vis[to] = 1; nt[now] = to; now = to; to = e[to][0]; } } vc[i].pb({to,ct}); } else { for(int j = 0; j < e[i].size(); ++j){ vc[i].pb({e[i][j],0}); } } } memset(vis, 0, sizeof vis); dfs(1, 1, 1); puts("There is no route, Karl!"); return 0; } /* 10 11 10 8 5 4 9 1 4 3 7 2 2 6 6 5 8 9 1 7 10 3 3 10 */
L:Landscape Improved
题解:直接模拟就好了,我们可以发现不好同时维护左边的信息,维护右边的信息,所以我们可以把他们分开来处理,最后在把所有的信息合在一起。
代码:
#include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); #define LL long long #define ULL unsigned LL #define fi first #define se second #define pb push_back #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lch(x) tr[x].son[0] #define rch(x) tr[x].son[1] #define max3(a,b,c) max(a,max(b,c)) #define min3(a,b,c) min(a,min(b,c)) typedef pair<int,int> pll; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const LL mod = (int)1e9+7; const int N = 1e5 + 100; LL h[N], hh[N]; LL m; int n; bool check(LL x){ memset(hh, 0, sizeof hh); LL s = 0, r = 2, l = n-1; for(int i = 1; i <= n; ++i){ if(r == i) r = i+1, s = 0; while(r <= n && h[r] < x - (r-i)){ s += x - (r-i) - h[r]; r++; } // cout << i << ' ' << r << ' ' << s << endl; if(r > n) hh[i] = INF; else { hh[i] = s; s -= max(0ll, (x-1)-h[i+1]); s += max(0ll, (r-1)-(i+1)); // cout << s << endl; } } s = 0; for(int i = n; i >= 1; --i){ if(l == i) l = i-1, s = 0; while(l >= 1 && h[l] < x - (i-l)){ s += x - (i-l) - h[l]; l--; } if(l < 1) hh[i] = INF; else { hh[i] += s; s -= max(0ll, (x-1)-h[i-1]); s += max(0ll, (i-1)-(l+1)); } } for(int i = 1; i <= n; ++i){ hh[i] += max(0ll, x-h[i]); if(hh[i] <= m) return true; } return false; } int main(){ freopen("landscape.in","r",stdin); freopen("landscape.out","w",stdout); scanf("%d%lld", &n, &m); LL mx = 0; for(int i = 1; i <= n; ++i){ scanf("%lld", &h[i]); mx = max(mx, h[i]); } LL l = mx+1, r = m + mod; while(l <= r){ LL mid = l+r >> 1; if(check(mid)) l = mid + 1; else r = mid - 1; } printf("%lld\n", l-1); return 0; }