20190823考试反思
这次考试CE了。
原因是我改了一个longlong没编译,然后最后查出来的时候已经没时间了。
不CE的话应该rk7左右。update:因为这个CE把我卡出了第一基房!!!!
但是都是暴力分。
T1:是一个规律题,给了5个样例,但我都没看出来,也是废了。我用背包A了
这个题首先是一道比较屎的背包都能想到。
但是转移会出错,原因在于:$f[j]|=f[(j-w[i]+k)%k]$这个东西转移顺序出问题了。
解决办法就是一个转移循环k次。
复杂度$O(nk^{2})$但是题目给了三个分档,k=100,k=1000,n,k=100000
首先100的肯定可以。
1000的就会出问题。但是有一个剪枝就是每次转移的时候转移完看看答案是否变化,如果不变化那么很显然就不用在循环接下来的保证正确性的k次循环。经过实测在100次左右答案就不在变化,复杂度可过。
100000的nk就死了,那么没办法,n的循环不能省,但是k的循环……,我可以随机找一个容积更新,大概随机次数在200次之后就稳定了。所以。。。。。n*?似乎可过????
数据貌似卡不了我复杂度,正解$O(nlogn)$,n极限在1e5,然后内层循环能循环250。。,因为他即使是构造的,但我仍是随机看人品更新的
然后多交两次就A了。
其实正确率还是蛮高的,在控制使n*k<=25000000的时候接近100%
n*k<=10000000的时候交3次WA1次。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> using namespace std; const int N=1000020; int w[N],a[N],f[N],cnt; long long rd() { long long s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } int main() { //freopen("math5.in","r",stdin); srand(unsigned(time(0))); int n=rd(),k=rd(); for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<=n;i++) { if(!f[a[i]%k]) { f[a[i]%k]=1; w[++cnt]=a[i]%k; } } int ans=0; sort(w+1,w+cnt+1,greater<int>()); if(n==1) { int gcd=a[1]%k; for(int i=1;i<=k;i++) f[1ll*gcd*i%k]=1; for(int i=0;i<k;i++) ans=ans+f[i]; printf("%d\n",ans); for(int i=0;i<k;i++) if(f[i]) printf("%d ",i); puts(""); return 0; return 0; } if(k<=100) { for(int i=1;i<=cnt;i++) { for(int p=1;p<=k;p++) { int sum=0; for(int j=0;j<k;j++) { f[j]|=f[(j-w[i]+k)%k]; sum+=f[j]; } if(ans==sum) break; ans=max(ans,sum); } } printf("%d\n",ans); for(int i=0;i<k;i++) if(f[i])printf("%d ",i); puts(""); return 0; } else if(k<=1000) { for(int i=1;i<=cnt;i++) { for(int p=1;p<=k;p++) { int sum=0; for(int j=0;j<k;j++) { f[j]|=f[(j-w[i]+k)%k]; sum+=f[j]; } if(sum==ans) break; else ans=max(ans,sum); } } printf("%d\n",ans); for(int i=0;i<k;i++) if(f[i])printf("%d ",i); puts(""); return 0; } else { for(register int i=1;i<=cnt;++i) { for(register int p=1;p*cnt<=25000000;++p) { const int j=rand()%k; f[j]|=f[(j-w[i]+k)%k]; } } for(register int i=0;i<k;i++) ans+=f[i]; printf("%d\n",ans); for(register int i=0;i<k;i++) if(f[i])printf("%d ",i); puts(""); return 0; } } /* g++ -std=c++11 1.cpp -o 1 ./1 2 8 4 12 */
T2:我做这题头脑很屎。一开始打了$O(n^{3}m^{3})$的打法,只能过暴搜。
然后硬是转成图论题topu强行降成$O(n^{2}m^{2})$以为A了。(事实上只是把DP之间问题和子问题的关系图建出来了)
结果后来发现数据范围只能$O(nm)$可过。
然后我就暴毙了,
方程想复杂了。
优化其实用4个树状数组维护拆开绝对值后的最大值就行了。
但是发现不用树状数组决策不会更劣因为在求最大值。
直接用变量。
#include<algorithm> #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; const int N=4020; int a[N][N],b[N][N],la[N*N],n,m,tt,cnt; long long f[N][N],ans; struct node{int x,y;}; struct bitar { long long bin[N][N]; void add(int x,int y,long long w) { for(register int i=x;i<=n;i+=(i&-i)) for(register int j=y;j<=m;j+=(j&-j)) bin[i][j]=max(bin[i][j],w); } long long ask(int x,int y) { long long sum=-0x7fffffff; for(register int i=x;i;i-=(i&-i)) for(register int j=y;j;j-=(j&-j)) sum=max(sum,bin[i][j]); return sum; } }aw,dw,as,ds; int rd() { register int s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } int main() { //freopen("biology4.in","r",stdin); n=rd(),m=rd(); int mini=0x7fffffff; for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) { a[i][j]=rd(); if(a[i][j]) la[++tt]=a[i][j]; } sort(la+1,la+tt+1); int len=unique(la+1,la+tt+1)-la-1; vector<node> p[len+2]; for(register int i=1;i<=n;++i) for(register int j=1;j<=m;++j) { int tmp=lower_bound(la+1,la+len+1,a[i][j])-la; p[tmp].push_back((node){i,j}); b[i][j]=rd(); } long long ask1=0,ask2=0,ask3=0,ask4=0; for(int t=1;t<=len;t++) { for(int k=0;k<p[t].size();k++) { int i=p[t][k].x,j=p[t][k].y; if(t==1) f[i][j]=b[i][j]; else f[i][j]=max(f[i][j],max(max(ask1+i+j,ask2+i-j),max(ask3-i+j,ask4-i-j))+b[i][j]); } for(int k=0;k<p[t].size();k++) { int i=p[t][k].x,j=p[t][k].y; ask1=max(ask1,f[i][j]-i-j);ask2=max(ask2,f[i][j]-i+j); ask3=max(ask3,f[i][j]+i-j);ask4=max(ask4,f[i][j]+i+j); ans=max(ans,f[i][j]); } } printf("%lld\n",ans); } /* g++ 1.cpp -o 1 ./1 3 3 1 2 3 4 5 6 7 8 9 7 8 9 7 6 4 2 10 8 */
T3:我又不会异或。。。。
第一问直接用桶存位即可。
第二问用一个可持久化trie树维护区间中异或a的值>b的个数。
和数位DP一样记忆化搜索即可。
#include<iostream> #include<vector> #include<cstdio> #include<cstring> using namespace std; const int mod=1e9+7; const int N=100020; int a[N],f[N][25],mac[30],rt[N],tt,stack[N],top,lm[N],rm[N]; bool b[N],c[N]; struct trie{int l,r,s;}tr[N*25]; long long rd() { long long s=0,w=1; char cc=getchar(); while(cc<'0'||cc>'9'){if(cc=='-') w=-1;cc=getchar();} while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar(); return s*w; } void build(int x,int &k,int len) { k=++tt;tr[k]=tr[x]; if(len==0){tr[k].s++;return;} if(b[len]==0) build(tr[x].l,tr[k].l,len-1); else build(tr[x].r,tr[k].r,len-1); tr[k].s=tr[tr[k].l].s+tr[tr[k].r].s; } int dfs(int k,int len,int lim) { if(!k) return 0; if(!lim) return tr[k].s; if(len==0) return lim^1; long long ans=0; if((b[len]^0)>=c[len])ans=(ans+dfs(tr[k].l,len-1,lim&&((b[len]^0)==c[len])))%mod; if((b[len]^1)>=c[len]) ans=(ans+dfs(tr[k].r,len-1,lim&&((b[len]^1)==c[len])))%mod; return ans; } int main() { int n=rd(),opt=rd();long long ans1=0,ans2=0;mac[0]=1; for(int i=1;i<=25;i++) mac[i]=mac[i-1]<<1; for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<=n;i++) { for(int j=0;j<=22;j++) f[i][j]=f[i-1][j]+((a[i]&mac[j])!=0); for(int k=1,x=a[i];k<=22;k++,x>>=1) b[k]=(x&1); build(rt[i-1],rt[i],22); } a[0]=a[n+1]=0x7fffffff; for(int i=0;i<=n+1;i++) { while(top>0&&a[stack[top]]<a[i]) rm[stack[top]]=i,top--; stack[++top]=i; }top=0; for(int i=n+1;i>=0;i--) { while(top>0&&a[stack[top]]<=a[i]) lm[stack[top]]=i,top--; stack[++top]=i; } for(int i=1;i<=n;i++) { for(int k=1,x=a[i];k<=22;k++,x>>=1)c[k]=(x&1); if(i-lm[i]<rm[i]-i) { for(int j=lm[i]+1;j<=i;j++) { for(int k=1,x=a[j];k<=22;k++,x>>=1) b[k]=(x&1); ans2=(ans2+1ll*a[i]*(dfs(rt[rm[i]-1],22,1)-dfs(rt[i-1],22,1)+mod)%mod)%mod; for(int k=0;k<=22;k++) { if(a[j]&mac[k])ans1=(ans1+1ll*a[i]*mac[k]%mod*(rm[i]-i+mod-(f[rm[i]-1][k]-f[i-1][k]+mod)%mod+mod)%mod)%mod; else ans1=(ans1+1ll*a[i]*mac[k]%mod*(f[rm[i]-1][k]-f[i-1][k]+mod)%mod)%mod; } } } else { for(int j=i;j<rm[i];j++) { for(int k=1,x=a[j];k<=22;k++,x>>=1) b[k]=(x&1); ans2=(ans2+1ll*a[i]*(dfs(rt[i],22,1)-dfs(rt[lm[i]],22,1)+mod)%mod)%mod; for(int k=0;k<=22;k++) { if(a[j]&mac[k])ans1=(ans1+1ll*a[i]*mac[k]%mod*(i-lm[i]+mod-(f[i][k]-f[lm[i]][k]+mod)%mod+mod)%mod)%mod; else ans1=(ans1+1ll*a[i]*mac[k]%mod*(f[i][k]-f[lm[i]][k]+mod)%mod)%mod; } } } } if(opt==1) printf("%lld\n",ans1); if(opt==2) printf("%lld\n",ans2); if(opt==3) printf("%lld\n%lld\n",ans1,ans2); return 0; } /* g++ -std=c++11 2.cpp -o 2 ./2 */