C - Bugged
题意:类似装箱问题,但是最后体积总和不能为10的倍数。
#include<cstdio> #include<cstring> #include<algorithm> #define MN 30001 using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } const int MOD=1e9+7; int n,a[11000],w; int main(){ int i,j,k; n=read(); a[0]=1; while(n--){ w=read(); for (i=10000;i>=0;i--) a[i+w]|=a[i]; } for (i=10000;i>=0;i--) if (a[i]&&i%10) return printf("%d ",i),0; puts("0"); }
D - Widespread
题意:n只怪物,每只有一个生命值,每次攻击可以指定一只造成A点伤害,其他所有造成B点伤害(A>B),问全部消灭的最小攻击次数。
题解:二分攻击次数。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define MN 300001 #define int long long using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } const int MOD=1e9+7; int n,a[110000],w=0,mmh=0,A,B,L=0,R=1e9; inline bool ju(int x){ int u=B*x,s=0; for (int i=1;i<=n;i++) if (a[i]>u) s+=(a[i]-u+A-1)/A; return s<=x; } signed main(){ int i,j,k; n=read();A=read();B=read();A-=B; for (i=1;i<=n;i++) a[i]=read(); while (L<R){ int mid=L+R>>1; if (ju(mid)) R=mid;else L=mid+1; } printf("%lld ",L); }
E - Meaningful Mean
题意:求一个数组中,平均值不小于k的连续子序列个数。
题解:全部减k之后数据结构处理前缀和即可。
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define MN 210001 #define int long long using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } const int MOD=1e9+7,M=1e15; int n,a[MN],ro=0,mmh=0,k,ls[MN*30],rs[MN*30],s[MN*30],NUM=0; void add(int &p,int l,int r,int k){ if (!p) p=++NUM,ls[p]=rs[p]=s[p]=0; s[p]++; if (l==r) return; int mid=l+r>>1; if (k<=mid) add(ls[p],l,mid,k);else add(rs[p],mid+1,r,k); } int ask(int p,int l,int r,int k){ if (!p) return 0; if (r<=k) return s[p]; int mid=l+r>>1; if (k<=mid) return ask(ls[p],l,mid,k);else return ask(rs[p],mid+1,r,k)+ask(ls[p],l,mid,k); } signed main(){ int i,j,k; n=read();k=read(); add(ro,-M,M,0); for (i=1;i<=n;i++){ a[i]=read()-k;a[i]+=a[i-1]; mmh+=ask(ro,-M,M,a[i]); add(ro,-M,M,a[i]); } printf("%lld ",mmh); }
F - Mirrored
题意:记rev(N)为把N在10进制下翻转以后的值(无前导0),给出D,求rev(N)=N+D的N的数量。
题解:好开心在考场上搞了出来。其实就是个暴力。枚举N的位数d,再同时枚举第i和d+1-i位,这样可以确定差中第i位和第d+1-i位的可能值,从而实现剪枝。然后你会发现这玩意可以记忆化……
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define MN 21001 #define int long long using namespace std; int read_p,read_ca; inline int read(){ read_p=0;read_ca=getchar(); while(read_ca<'0'||read_ca>'9') read_ca=getchar(); while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar(); return read_p; } const int MOD=1e9+7; int n,a[MN],B[MN],x,mmh=0,mm[20][20][2][2]; inline int M(int x){return x<0?x+10:x;} inline void work(int p,int n,int a,int b){ if (mm[p][n][a][b]!=-1) {mmh+=mm[p][n][a][b];return;} int u=mmh; if (p+p-1==n){ if (a==0&&b==0) mmh+=10*(B[p]==0);else if (a==1&&b==1) mmh+=10*(B[p]==9); return; } if (p+p-1>n){ mmh+=a==b; return; } for (int i=p==1;i<=9;i++) for (int j=0;j<=9;j++) if (M(i-j-b)==B[p]&&(a==(j<i)||j==i)&&(M(j-i)==B[n+1-p]||M(j-1-i)==B[n+1-p])){ if (a){ if (j==i&&B[n+1-p]==0) continue; work(p+1,n,M(j-1-i)==B[n+1-p],i-b-j<0); }else{ if (j==i&&B[n+1-p]==9) continue; work(p+1,n,M(j-1-i)==B[n+1-p],i-b-j<0); } } mm[p][n][a][b]=mmh-u; } signed main(){ int i,j,k; x=n=read(); if (n%9) return puts("0"),0; for (k=1;k<=10&&x;k++) B[k]=x%10,x/=10;k--; for (int i=k;i<=18;i++) memset(mm,-1,sizeof(mm)),work(1,i,0,0); printf("%lld ",mmh); }
涨rating啦好开心