第一题是鼎纹。小块的1去匹配大块的1。
记录一下1的位置,然后模拟即可。
而且考试的时候没有记录大块的1的位置。记录的话可以更快。
但是考试时写的还有什么不对?就算把 if ( ! cx )改成用vis判断也还是不对!
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1005; int T,n,m,nn,mm,a[N][N],b[N][N],tot,cnt; bool flag; struct Node{ int x,y; }nt[N]; void init() { int cx=0; for(int i=1;i<=nn;i++) for(int j=1;j<=mm;j++) if(b[i][j]) { if(!cx)cx=i; nt[++tot].x=i-cx+1;nt[tot].y=j; } } int main() { freopen("grain.in","r",stdin); freopen("grain.out","w",stdout); scanf("%d",&T); while(T--) { cnt=0;tot=0;flag=0; scanf("%d%d%d%d",&n,&m,&nn,&mm); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) { scanf("%1d",&a[i][j]);if(a[i][j])cnt++; } for(int i=1;i<=nn;i++)for(int j=1;j<=mm;j++)scanf("%1d",&b[i][j]); init(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(a[i][j]) { int fx=i-1,fy=j-nt[1].y; for(int k=1;k<=tot;k++) { int x=nt[k].x+fx,y=nt[k].y+fy; if(x<1||x>n||y<1||y>n||a[x][y]!=1){flag=1;break;} a[x][y]=0;cnt--; } if(flag)break; } if(flag)break; } if(flag||cnt)printf("NO\n"); else printf("YES\n"); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int N=1005; int T,n,m,nn,mm,cnt,ynt; char a[N][N],b[N][N]; bool flag; struct Node{ int x,y; }ct[N*N],yt[N*N]; int read() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } void init() { cnt=0; for(int i=1;i<=nn;i++) for(int j=1;j<=mm;j++) if(b[i][j]=='1') { ct[++cnt].x=i;ct[cnt].y=j; } ynt=0; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(a[i][j]=='1')yt[++ynt].x=i,yt[ynt].y=j; } int main() { freopen("grain.in","r",stdin); freopen("grain.out","w",stdout); T=read(); while(T--) { n=read();m=read();nn=read();mm=read(); for(int i=1;i<=n;i++)scanf("%s",a[i]+1); for(int i=1;i<=nn;i++)scanf("%s",b[i]+1); init(); for(int l=1;l<=ynt;l++) { if(a[yt[l].x][yt[l].y]=='0')continue; int fx=yt[l].x-ct[1].x,fy=yt[l].y-ct[1].y; for(int k=1;k<=cnt;k++) { int x=ct[k].x+fx,y=ct[k].y+fy; if(x>=1&&x<=n&&y>=0&&y<=m&&a[x][y]=='1')a[x][y]='0'; else { flag=1;break; } } if(flag)break; } if(flag)printf("NO\n"),flag=0; else printf("YES\n"); } return 0; }
第二题是LICS模板+输出方案。
一定要记住n^2的LICS模板!记录pre需要带上第一维,不知道为什么。可能省掉第一维后pre可能重复?
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; const int N=5005; int n,m,tot,f[N<<1],dp[N]; ll a[N],b[N],id[N<<1],tp[N<<1],pre[N<<1],v[N<<1]; int read() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } int readl() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } void init() { sort(tp+1,tp+n+m+1);tot=unique(tp+1,tp+n+m+1)-tp-1;// for(int i=1;i<=n;i++){ ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp; } for(int i=1;i<=m;i++){ ll tmp=b[i];b[i]=lower_bound(tp+1,tp+tot+1,b[i])-tp;id[b[i]]=tmp; } } void add(ll x,int k) { ll tx=x; for(;x<=tot;x+=(x&-x)) if(k>f[x]) f[x]=k,v[x]=tx;//v:f记录的max(长度)指向的是哪个值 } int query(ll k) { int mx=0;ll x=k-1; for(;x;x-=(x&-x)) if(f[x]>mx) mx=f[x],pre[k]=v[x];//pre:以k结尾的上一个值 return mx; } int main() { freopen("sail.in","r",stdin); freopen("sail.out","w",stdout); n=read(); for(int i=1;i<=n;i++)a[i]=readl(),tp[i]=a[i]; m=read(); for(int i=1;i<=m;i++)b[i]=readl(),tp[i+n]=b[i]; init(); for(int i=1;i<=n;i++) { memset(f,0,sizeof f); for(int j=1;j<=m;j++) { add(b[j],dp[j]); if(a[i]==b[j])dp[j]=query(b[j])+1; } for(int j=1;j<=m;j++)add(b[j],dp[j]); } tot++; int ans=query(tot),cnt=0; while(pre[tot])tp[++cnt]=pre[tot],tot=pre[tot]; printf("%d\n",ans); for(int i=cnt;i;i--)printf("%lld ",id[tp[i]]); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define ll long long using namespace std; const int N=5005; int n,m,ans,rd,cnt,dp[N],pre[N]; ll a[N],b[N],as[N]; ll red() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } int read() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } int main() { freopen("sail.in","r",stdin); freopen("sail.out","w",stdout); n=read();for(int i=1;i<=n;i++)a[i]=red(); m=read();for(int i=1;i<=m;i++)b[i]=red(); for(int i=1;i<=n;i++) { ll mx=0;int pos=0; for(int j=1;j<=m;j++) if(a[i]==b[j]&&mx+1>dp[j]) { dp[j]=mx+1;pre[j]=pos; if(dp[j]>ans)ans=dp[j],rd=j; } else if(b[j]<a[i]&&dp[j]>mx)mx=dp[j],pos=j; } printf("%d\n",ans); while(rd) { as[++cnt]=rd;rd=pre[rd]; } for(int i=cnt;i;i--)printf("%lld ",b[as[i]]); return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #define ll long long using namespace std; const int N=5005; int n,m,ans,rd,cnt,dp[N][N],pre[N][N]; ll a[N],b[N],as[N]; ll red() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } int read() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch<='9'&&ch>='0')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } int main() { freopen("sail.in","r",stdin); freopen("sail.out","w",stdout); n=read();for(int i=1;i<=n;i++)a[i]=red(); m=read();for(int i=1;i<=m;i++)b[i]=red(); for(int i=1;i<=n;i++) { ll mx=0;int pos=0; for(int j=1;j<=m;j++) if(a[i]==b[j]&&mx+1>dp[i][j]) { dp[i][j]=mx+1;pre[i][j]=pos; if(dp[i][j]>ans)ans=dp[i][j],rd=j; } else if(a[i]!=b[j]) { dp[i][j]=dp[i-1][j]; if(b[j]<a[i]&&dp[i][j]>mx)mx=dp[i][j],pos=j; } } printf("%d\n",ans,rd); for(int i=n;rd;i--) { if(a[i]==b[rd])as[++cnt]=rd,rd=pre[i][rd]; } for(int i=cnt;i;i--)printf("%lld ",b[as[i]]); return 0; }
第三题是莫队。
考试时想到莫队,却不知道怎么O(1)查询。后来得知莫队的正确用法!
mx一定是边扩展边求的。利用每一块内的 r 递增的性质,不用在意 r 。
关键是每一块的 l 可能需要减某些值。mx是不支持减的。
所以对于每个 l 可以从它所在的块的右端点每次暴力扩展到它!
换 l 的时候把 l 到 r 整个暴力一遍就行。复杂度 nsqrt(n) 。
题解给的方法慢多了。是把整块的信息记录下来,每次 l 和 r 两端暴力。
!!这两种方法都不能随便用memset,不然会慢得不行!!!所以清空值就再跑一遍刚才的循环。这比memset快多了!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #define ll long long using namespace std; const int N=1e5+5,K=315; int n,m,base,tot; ll a[N],tp[N],id[N],sum[N],mx; ll mxx[N/K+5][N/K+5],s[N/K+5][N]; struct Ques{ int l,r,bh,id; }q[N]; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } ll rdl() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } bool cmp(Ques a,Ques b){return a.bh==b.bh?a.r<b.r:a.bh<b.bh;} int hb(int a){return (a-1)/base+1;} void init() { int nt=hb(n); for(int i=1;i<=nt;i++) { int d=min(i*base,n); for(int j=(i-1)*base+1;j<=d;j++)s[i][a[j]]+=id[a[j]]; } for(int i=1;i<=nt;i++)for(int j=1;j<=tot;j++)s[i][j]+=s[i-1][j]; for(int i=1;i<=nt;i++) for(int j=i;j<=nt;j++) { mxx[i][j]=mxx[i][j-1]; int d=min(j*base,n); for(int k=(j-1)*base+1;k<=d;k++)mxx[i][j]=max(mxx[i][j],s[j][a[k]]-s[i-1][a[k]]); } } int main() { freopen("mode.in","r",stdin); freopen("mode.out","w",stdout); n=rdn();m=rdn();for(int i=1;i<=n;i++)tp[i]=a[i]=rdl(); sort(tp+1,tp+n+1);tot=unique(tp+1,tp+n+1)-tp-1; for(int i=1;i<=n;i++) { ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp; } base=sqrt(n); for(int i=1;i<=m;i++) { q[i].l=rdn();q[i].bh=hb(q[i].l);q[i].r=rdn();q[i].id=i; } init(); for(int i=1,qd;i<=m;i++) { if(hb(q[i].r)-q[i].bh<=1) { mx=0; for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]); for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]-=id[a[j]]; printf("%lld\n",mx);continue; } int x=q[i].bh,y=hb(q[i].r); mx=mxx[x+1][y-1];qd=q[i].bh*base; for(int j=q[i].l;j<=qd;j++) sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]+s[y-1][a[j]]-s[x][a[j]]); for(int j=(y-1)*base+1;j<=q[i].r;j++) sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]+s[y-1][a[j]]-s[x][a[j]]); for(int j=q[i].l;j<=qd;j++)sum[a[j]]-=id[a[j]]; for(int j=(y-1)*base+1;j<=q[i].r;j++)sum[a[j]]-=id[a[j]]; printf("%lld\n",mx); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #define ll long long using namespace std; const int N=1e5+5; int n,m,base,tot; ll a[N],tp[N],id[N],sum[N],mx,tsum[N],tmx,ans[N]; struct Ques{ int l,r,bh,id; }q[N]; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } ll rdl() { ll ret=0;char ch=getchar(); while(ch>'9'||ch<'0')ch=getchar(); while(ch>='0'&&ch<='9')(ret*=10)+=(int)ch-'0',ch=getchar(); return ret; } bool cmp(Ques a,Ques b){return a.bh==b.bh?a.r<b.r:a.bh<b.bh;} int hb(int a){return (a-1)/base+1;} int main() { freopen("mode.in","r",stdin); freopen("mode.out","w",stdout); n=rdn();m=rdn();for(int i=1;i<=n;i++)tp[i]=a[i]=rdl(); sort(tp+1,tp+n+1);tot=unique(tp+1,tp+n+1)-tp-1; for(int i=1;i<=n;i++) { ll tmp=a[i];a[i]=lower_bound(tp+1,tp+tot+1,a[i])-tp;id[a[i]]=tmp; } base=sqrt(n); for(int i=1;i<=m;i++) { q[i].l=rdn();q[i].bh=hb(q[i].l);q[i].r=rdn();q[i].id=i; } sort(q+1,q+m+1,cmp); for(int i=1,qd,dr;i<=m;) { while(hb(q[i].r)==q[i].bh&&i<=m) { mx=0; for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]+=id[a[j]],mx=max(mx,sum[a[j]]); for(int j=q[i].l;j<=q[i].r;j++)sum[a[j]]-=id[a[j]]; ans[q[i].id]=mx;i++; } if(i>m)break; mx=0; qd=q[i].bh*base+1; for(dr=qd;dr<=q[i].r;dr++)sum[a[dr]]+=id[a[dr]],mx=max(mx,sum[a[dr]]); do{ for(;dr<=q[i].r;dr++)sum[a[dr]]+=id[a[dr]],mx=max(mx,sum[a[dr]]); tmx=mx; for(int j=q[i].l;j<qd;j++)tsum[a[j]]+=id[a[j]],tmx=max(tmx,tsum[a[j]]+sum[a[j]]); for(int j=q[i].l;j<qd;j++)tsum[a[j]]-=id[a[j]]; ans[q[i].id]=tmx;i++; }while(q[i].bh==q[i-1].bh&&i<=m); for(int j=qd;j<=q[i-1].r;j++)sum[a[j]]-=id[a[j]]; } for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); return 0; }