CF666Div2题解与总结
先放个链接:https://codeforc.es/contest/1397
中规中矩的一场比赛吧,但没有AK...考场最后一题没过,赛后想想主要原因还是D题意看错,(英文不好),导致打得很慢(同样A4题,有人rk30,我rk400)
写个简单题解吧,重点讲一下C和E
A题:送分题,没什么好说的,判一下字母数是否平均分成n份就做完了
/*A. Juggling Letters*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long char str[1010]; int cnt[27]; int main() { int t; cin >> t; while(t--){ memset(cnt,0,sizeof(cnt)); int n; scanf("%d",&n); for(int i = 1; i <= n; ++i){ scanf("%s",str+1); int len = strlen(str+1); for(int j = 1; j <= len; ++j) cnt[str[j] - 'a']++; } bool flag = true; for(int i = 0; i <= 'z' - 'a'; ++i){ if(cnt[i] % n) flag = false; } if(flag) puts("YES"); else puts("NO"); } return 0; }
B题依然送分,题面看着很可怕,但其实我们可以意识到c^n次方非常大(即有很多情况是可以提前判掉的),所以可以暴枚这个数组,然后有个显然的贪心就是给定两个数组a,b,要最小化∑|ai -bi|,就要把a,b排序后按位减
/*B. Power Sequence*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define ll long long const int maxn = 1e5 + 10; ll a[maxn],p[maxn]; int read(){ char c = getchar(); int x = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar(); return x; } const ll inf = 1e15; int main() { int n = read(); ll ans = 2e18; for(int i = 0; i < n; ++i) a[i] = read(); sort(a,a+n) ; ll x = 1; while(1){ bool flag = false; p[0] = 1; for(int i = 1; i < n; ++i){ p[i] = p[i-1] * x; if(p[i] >= inf){ flag = true; break; } } if(flag) break; x++; ll res = 0; for(int i = 0; i < n; ++i) res += abs(p[i] - a[i]); ans = min(ans,res); } printf("%lld\n",ans); return 0; }
C题比较有意思,为什么构造是3次?我们可以先把an搞成0(这个是显然可以的,因为任何数都是1的倍数),然后分别对1~n-1,1~n搞,问题就转化为求a * (n-1) - b * n = -a[i]
因为对于任意n,都有gcd(n,n-1) = 1,所以根据Bezout定理,这个不定方程一定有整数解,拓欧求一下即可
/*C. Multiples of Length*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn = 1e5 + 10; int a[maxn]; ll b[maxn]; int read(){ int f = 1; int x = 0; char c = getchar(); while(c < '0' || c > '9') f = (c == '-')?-1:f,c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar(); return x * f; } ll exgcd(ll a,ll b,ll &x,ll &y){ if(b == 0){ x = 1,y = 0; return a; } ll d = exgcd(b,a%b,x,y); ll z = x;x = y;y = z - (a / b) * y; return d; } int main() { int n = read(); for(int i = 1; i <= n; ++i) a[i] = read(); if(n == 1){ printf("1 1\n"); printf("%d\n",-1*a[1]); printf("1 1\n0\n"); printf("1 1\n0\n"); return 0; } if(n == 2){ printf("1 1\n%d\n",-1*a[1]); printf("2 2\n%d\n",-1*a[2]); printf("1 1\n0\n"); return 0; } if(n == 3){ printf("1 1\n%d\n",-1*a[1]); printf("2 2\n%d\n",-1*a[2]); printf("3 3\n%d\n",-1*a[3]); return 0; } ll x = 0,y = 0; exgcd(n,n-1,x,y); printf("1 1\n%d\n",-1*a[1]); printf("%d %d\n",2,n); for(int i = 2; i <= n; ++i){ printf("%lld ",1ll * x * (n - 1) * a[i]); } puts(""); printf("%d %d\n",1,n); for(int i = 1; i <= n; ++i){ if(i == 1) printf("%d ",0); else printf("%lld ",1ll * y * n * a[i]); } return 0; }
D题不说了,简单贪心,每次取能取的最大,就过了
/*Stoned Games*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define ll long long int a[110]; struct Num{ int id,v; }; bool operator < (Num A,Num B) { return A.v < B.v; } priority_queue<Num>q; int read(){ char c = getchar(); int x = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar(); return x; } int main() { int t = read(); while(t--){ int n = read(); while(!q.empty()) q.pop(); for(int i = 1; i <= n; ++i) a[i] = read(),q.push(Num{i,a[i]}); int cnt = 0; int lst = 0; while(1){ if(q.empty()) break; Num now = q.top();Num A; if(now.id == lst){ //if(q.empty()) break; q.pop(); if(q.empty()) break; A = q.top(); q.pop(); lst = A.id; if(A.v >= 2) q.push(Num{A.id,A.v-1}); q.push(now); } else{ lst = now.id; q.pop(); if(now.v >= 2) q.push(Num{now.id,now.v-1}); } cnt++; } if(cnt & 1) puts("T"); else puts("HL"); } return 0; }
E题比较有意思,对于这种有一堆操作的,一般都只有几种操作有用,其实可以发现,对于一组怪,要么直接全部杀死,要么就只有boss剩1滴血,又因为每组怪都要处理,所以最优解钟最多只有前一个的怪还没有打完(即boss剩一滴血的情况),所以可以根据这个性质DP,具体看代码,有注释
/*E Monster Invader*/ #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define ll long long const int maxn = 1e6 + 10; ll f[maxn][2];/*f[i][0] (1~i has finished) f[i][1] (only the boss of i hasn't finished)*/ ll A[maxn],B[maxn],C[maxn]; ll read(){ char c = getchar(); ll x = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48,c = getchar(); return x; } int a[maxn]; int main() { int n = read(); ll r1 = read(),r2 = read(),r3 = read(),d = read(); for(int i = 1; i <= n; ++i) a[i] = read(); memset(f,0x3f,sizeof(f)); f[0][0] = 0; for(int i = 1; i <= n; ++i){ A[i] = min(min(r2,r1),r3);/*一击必杀最小代价*/ B[i] = min(r3,r1) * a[i] + r3;/*直接清理掉的最小代价*/ C[i] = min((min(r3,r1) * a[i] + r1),r2);/*剩boss一滴血的最小代价*/ } for(int i = 1; i <= n; ++i) { if(i == 1) f[i][0] = B[i],f[i][1] = f[i-1][0] + C[i]; else{ int k = (i == n)?2:3; f[i][0] = min(min(f[i-1][0] + B[i] + d,f[i-1][0] + C[i] + 3 * d + A[i]),min(f[i-1][1] + k * d + B[i] + A[i-1], f[i-1][1] + 3 * d + C[i] + A[i-1] + A[i])); f[i][1] = f[i-1][0] + C[i] + d; } //printf("f[%d][0] = %lld f[%d][1] = %lld\n",i,f[i][0],i,f[i][1]); } printf("%lld\n",f[n][0]); return 0; }