前言
- 最近考试考得最差的一次吧。
- 考试的时候太浮躁了,T2题都读错。
- 其实读错题没什么,主要是T1连对拍都不打,于是一些非常智障的错误导致本应AC的代码变成WA0。
- 以后考试有时间的话对拍还是尽量题题都打……
T1
- 这场考试也挺奇怪的,我感觉T1应该是三个题里最难的。
- 考试的时候刚开始一直觉得直接快速幂就行,但后来发现需要考虑行间关系,便很自然的想到正解。
- 可以把%n后结果相同的列一起考虑,这样可以进行dp
- 设f[i][j]表示考虑了%n结果不大于i的所有列,一共放了j个棋子的方案数。
- 则$f[i][j]=sumlimits_{k=max(0,j-n)}^j f[i-1][j-k]*{{C_n^k}^{m/n+[m\%n>=i]}}$
- 显然可以滚动。
- 然后我就滚动不清空,爆零两行泪了……
- ${C_n^k}^{m/n+[m\%n>=i]}$这个东西可以预处理的。
- 所以时间复杂度为$Theta(N^4)$,空间复杂度$Theta(N^2)$。
- 注意有(应该有,我不确定)m<n的情况。
#include<cstdio> using namespace std; int const N=10002,M=102,mod=1e9+7; long long fac[N],inv[N]; long long cp[M]; long long f[2][N]; int cf[M]; long long cq[M][2]; inline long long power(long long x,long long y){ long long ans=1; for(;y;y>>=1,x=x*x%mod) if(y&1)ans=ans*x%mod; return ans; } inline long long C(int x,int y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; } inline int max(int x,int y){ return x>y?x:y; } int main(){ //freopen("3.in","r",stdin); //freopen("6.out","w",stdout); int n,c; long long m; scanf("%d%lld%d",&n,&m,&c); int lit=n*n,hh=m%n,pc=(m/n)%(mod-1); fac[0]=1; for(register int i=1;i<=lit;++i)fac[i]=fac[i-1]*i%mod; inv[lit]=power(fac[lit],mod-2); for(register int i=lit;i;--i)inv[i-1]=inv[i]*i%mod; for(register int i=0;i<=n;++i)cp[i]=C(n,i); for(register int i=1;i<=hh;++i)cf[i]=1; for(register int i=0;i<=n;++i) cq[i][0]=power(cp[i],pc),cq[i][1]=cq[i][0]*cp[i]%mod; int u=0,v=1; f[0][0]=1; if(m<n){ for(register int i=1;i<=m;++i,u=v,v^=1) for(register int j=0;j<=c;++j){ f[v][j]=0; for(register int k=max(0,j-n);k<=j;++k) f[v][j]=(f[v][j]+cq[j-k][1]*f[u][k])%mod; } printf("%lld",f[u][c]); return 0; } for(register int i=1;i<=n;++i,u=v,v^=1) for(register int j=0;j<=c;++j){ f[v][j]=0; for(register int k=max(0,j-n);k<=j;++k) f[v][j]=(f[v][j]+cq[j-k][cf[i]]*f[u][k])%mod; } printf("%lld",f[u][c]); return 0; }
T2
- 考试看成最长不下降子串,当场去世……
- 题意是只要左端点最小右端点最大就行,中间元素可不单调。
- 考虑从右向左扫描,维护一个单调不上升的栈。
- 把栈内元素当作右端点,维护栈内元素的左端点即可。
- 具体实现不是很好描述,请自行脑补(不行就颓码吧)。
- 时空复杂度$Theta(N)$
- 本题1e7的读入量,使用fread可以快3倍以上。
#include<cstdio> #define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++) using namespace std; int const N=1e7+5,L=2e8; char buf[L],*S,*T; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int max(int x,int y){ return x>y?x:y; } inline int min(int x,int y){ return x<y?x:y; } int a[N],stk[N],mx[N],top,ans=1; int pos[N]; int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); int n=read(); a[0]=1e9+7; for(register int i=1;i<=n;++i)a[i]=read(); for(register int i=n,x;i;--i){ x=a[i]; while(x>a[stk[top]]){ ans=max(ans,stk[top]-pos[top]+1); if(top^1 && mx[top-1]>=a[pos[top]])pos[top-1]=pos[top]; mx[top-1]=min(mx[top-1],mx[top]),--top; } stk[++top]=i; pos[top]=i,mx[top]=a[i]; } while(a[0]>a[stk[top]]){ ans=max(ans,stk[top]-pos[top]+1); if(top^1 && mx[top-1]>=a[pos[top]])pos[top-1]=pos[top]; mx[top-1]=min(mx[top-1],mx[top]),--top; } printf("%d",ans); return 0; } /*5 3 8 7 5 9 */
T3
- 没什么好说的,原题,同permu。
- 才知道当时打的是回滚莫队……当时颓的题解也没说啊
- 时间复杂度$Theta(Nsqrt{N})$,空间复杂度$Theta(N)$。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int const N=1e5+5; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57)bb=getchar(); while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline int max(int x,int y){ return x>y?x:y; } int n,m; int a[N],stk[N],top; int as[N]; struct node{ int l,r,id; }q[N]; int bl[N],rb[N]; int bar[N],le[N],re[N]; int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(); int bk=sqrt(n),ct=n/bk,ln=0,rn=0; for(register int i=1;i<=ct;++i){ ln=rn+1,rn+=bk; rb[i]=rn; for(register int j=ln;j<=rn;++j)bl[j]=i; } if(rn<n){ rb[++ct]=n; for(register int j=rn+1;j<=n;++j)bl[j]=ct; } for(register int i=1;i<=n;++i)a[i]=read(); for(register int i=1;i<=m;++i)q[i].l=read(),q[i].r=read(),q[i].id=i; sort(q+1,q+m+1,[](node skyh,node yxs){ return (bl[skyh.l]^bl[yxs.l])?skyh.l<yxs.l:skyh.r<yxs.r; }); for(register int i=1,ans,tans,z;i<=m;++i){ if(bl[q[i].l]^bl[q[i-1].l]){ memset(bar,0,sizeof(bar)); memset(le,0,sizeof(le)); memset(re,0,sizeof(re)); rn=rb[bl[q[i].l]]; ans=tans=0; } //printf("%d %d %d ",q[i].l,q[i].r,rb[bl[q[i].l]]); if(q[i].r<=rb[bl[q[i].l]]){ for(register int j=q[i].r;j>=q[i].l;--j){ ++bar[stk[++top]=z=a[j]]; if(bar[z-1]&&bar[z+1]) le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1]; else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z; else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z; else le[z]=re[z]=z; tans=max(tans,re[z]-le[z]+1); } while(top){ z=stk[top--]; if(le[z]^z)re[le[z]]=z-1; if(re[z]^z)le[re[z]]=z+1; le[z]=re[z]=0,--bar[z]; } as[q[i].id]=tans,tans=0; continue; } //printf("%d ",rn); while(rn<q[i].r){ ++bar[z=a[++rn]]; if(bar[z-1]&&bar[z+1]) le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1]; else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z; else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z; else le[z]=re[z]=z; ans=max(ans,re[z]-le[z]+1); //printf("!!%d %d %d %d ",ans,z,re[z],le[z]); }//printf("%d ",ans); tans=ans; for(register int j=rb[bl[q[i].l]];j>=q[i].l;--j){ ++bar[stk[++top]=z=a[j]]; if(bar[z-1]&&bar[z+1]) le[re[le[z-1]]=re[z]=re[z+1]]=le[z]=le[z-1]; else if(bar[z-1])re[le[z]=le[z-1]]=re[z]=z; else if(bar[z+1])le[re[z]=re[z+1]]=le[z]=z; else le[z]=re[z]=z; tans=max(tans,re[z]-le[z]+1); //printf("%d %d ",tans,z); } while(top){ z=stk[top--]; if(le[z]^z)re[le[z]]=z-1; if(re[z]^z)le[re[z]]=z+1; le[z]=re[z]=0,--bar[z]; } as[q[i].id]=tans; } for(register int i=1;i<=m;++i)printf("%d ",as[i]); return 0; }