T1
设$dp[i][j]$表示决策到第$i$个格子,此时第$i$个格子的水位线是$j$的最优解。考试的时候一直觉得直接线性DP有后效性,但是我们让低于隔板的部分从隔板下的部分取最大值转移,高于隔板的部分只从等于它的高度转移,就是 区间max+区间修改,用线段树合并优化成$O(nlog h)$
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005,M=1.2e7+70,Maxx=1e6,inf=1e9; 6 int h[N],root[N],son[M][2],mxx[M],laz[M]; 7 int T,n,m,z,t1,t2,t3,tot; 8 void i207M() 9 { 10 for(int i=1;i<=tot;i++) 11 son[i][0]=son[i][1]=mxx[i]=laz[i]=0; 12 for(int i=1;i<=n;i++) root[i]=0; tot=0; 13 } 14 void Pushup(int nde) 15 { 16 int ls=son[nde][0],rs=son[nde][1]; 17 mxx[nde]=max(ls?mxx[ls]:-inf,rs?mxx[rs]:-inf); 18 } 19 void Release(int nde) 20 { 21 int &ls=son[nde][0],&rs=son[nde][1]; 22 if(!ls) ls=++tot; if(!rs) rs=++tot; 23 if(laz[nde]) 24 { 25 int &lz=laz[nde]; 26 laz[ls]+=lz,laz[rs]+=lz; 27 mxx[ls]+=lz,mxx[rs]+=lz,lz=0; 28 } 29 } 30 void Change(int &nde,int l,int r,int ll,int rr,int tsk) 31 { 32 if(l>rr||r<ll) 33 return ; 34 else 35 { 36 if(!nde) nde=++tot; 37 if(l>=ll&&r<=rr) 38 mxx[nde]+=tsk,laz[nde]+=tsk; 39 else 40 { 41 int mid=(l+r)>>1; Release(nde); 42 Change(son[nde][0],l,mid,ll,rr,tsk); 43 Change(son[nde][1],mid+1,r,ll,rr,tsk); 44 Pushup(nde); 45 } 46 } 47 } 48 int Query(int &nde,int l,int r,int ll,int rr) 49 { 50 if(l>rr||r<ll) 51 return -inf; 52 else 53 { 54 if(!nde) return 0; 55 if(l>=ll&&r<=rr) 56 { 57 int ret=mxx[nde]; 58 nde=0; return ret; 59 } 60 else 61 { 62 int mid=(l+r)>>1; Release(nde); 63 return max(Query(son[nde][0],l,mid,ll,rr), 64 Query(son[nde][1],mid+1,r,ll,rr)); 65 } 66 } 67 } 68 int Merge(int x,int y) 69 { 70 if(!x||!y) return x+y; 71 if(!son[x][0]&&!son[x][1]) swap(x,y); 72 if(!son[y][0]&&!son[y][1]) 73 mxx[x]+=laz[y],laz[x]+=laz[y]; 74 else 75 { 76 Release(x),Release(y); 77 son[x][0]=Merge(son[x][0],son[y][0]); 78 son[x][1]=Merge(son[x][1],son[y][1]); 79 Pushup(x); 80 } 81 return x; 82 } 83 int main() 84 { 85 scanf("%d",&T); 86 while(T--) 87 { 88 scanf("%d%d",&n,&m),i207M(); 89 for(int i=2;i<=n;i++) 90 scanf("%d",&h[i]); 91 for(int i=1;i<=m;i++) 92 { 93 scanf("%d%d%d",&t1,&t2,&t3),t2++; 94 if(t3) Change(root[t1],0,Maxx,t2,Maxx,1); 95 else Change(root[t1],0,Maxx,0,t2-1,1); 96 } 97 for(int i=2;i<=n;i++) 98 { 99 int pm=Query(root[i-1],0,Maxx,0,h[i]); 100 Change(root[i],0,Maxx,0,h[i],pm); 101 root[i]=Merge(root[i-1],root[i]); 102 }//for(int i=1;i<=n;i++) 103 printf("%d ",Query(root[n],0,Maxx,0,Maxx)); 104 } 105 return 0; 106 }
T2
讲烂了的结论题.jpg
从一个未匹配点沿着未匹配-匹配边不断走,路上的点都是不一定在最大匹配里的
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=105,M=20005,E=100005,inf=1e9; 6 const int mov[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 7 int T,n,m,s,t,f,b,pts,ava,cnt,tot,maxx; 8 int p[M],pp[M],noww[E],goal[E],flow[E]; 9 int mapp[N][N],idx[N][N],dep[M],que[M],mat[M],ntp[M]; 10 char str[N]; 11 struct a 12 { 13 int x,y; 14 }ans[N]; 15 bool cmp(a xx,a yy) 16 { 17 return xx.x==yy.x?xx.y<yy.y:xx.x<yy.x; 18 } 19 bool Check(int x,int y) 20 { 21 return x>=1&&x<=n&&y>=1&&y<=m&&mapp[x][y]; 22 } 23 void Link(int f,int t,int v) 24 { 25 noww[++cnt]=p[f],p[f]=cnt; 26 goal[cnt]=t,flow[cnt]=v; 27 noww[++cnt]=p[t],p[t]=cnt; 28 goal[cnt]=f,flow[cnt]=0; 29 } 30 void Init(int st,int ed) 31 { 32 for(int i=1;i<=ed;i++) 33 pp[i]=p[i],dep[i]=-1; 34 dep[st]=0,que[f=b=0]=st; 35 } 36 bool Layering(int st,int ed) 37 { 38 Init(st,ed); 39 while(f<=b) 40 { 41 int tn=que[f++]; 42 for(int i=pp[tn];i;i=noww[i]) 43 if(flow[i]&&dep[goal[i]]==-1) 44 dep[goal[i]]=dep[tn]+1,que[++b]=goal[i]; 45 } 46 return ~dep[ed]; 47 } 48 int Augmenting(int nd,int ed,int mn) 49 { 50 if(nd==ed||!mn) return mn; 51 int tmp,tep=0; 52 for(int i=pp[nd];i;i=noww[i]) 53 { 54 pp[nd]=i; 55 if(dep[goal[i]]==dep[nd]+1) 56 if(tmp=Augmenting(goal[i],ed,min(mn,flow[i]))) 57 { 58 flow[i]-=tmp,mn-=tmp; 59 flow[i^1]+=tmp,tep+=tmp; 60 if(!mn) break; 61 } 62 } 63 return tep; 64 } 65 int Dinic_Maxflow() 66 { 67 int ret=0; 68 while(Layering(s,t)) 69 ret+=Augmenting(s,t,inf); 70 return ret; 71 } 72 void Match(int nde) 73 { 74 for(int i=p[nde];i;i=noww[i]) 75 if(!flow[i]&&goal[i]!=s) 76 mat[goal[i]]=nde,mat[nde]=goal[i]; 77 } 78 void Getans(int nde) 79 { 80 ntp[nde]=true; 81 for(int i=p[nde];i;i=noww[i]) 82 if(!ntp[mat[goal[i]]]) 83 Getans(mat[goal[i]]); 84 } 85 int main() 86 { 87 scanf("%d%d",&n,&m); 88 for(int i=1;i<=n;i++) 89 { 90 scanf("%s",str+1); 91 for(int j=1;j<=m;j++) 92 mapp[i][j]=str[j]=='.',idx[i][j]=++tot; 93 } 94 s=tot+1,t=s+1,cnt=1; 95 for(int i=1;i<=n;i++) 96 for(int j=1;j<=m;j++) 97 if(mapp[i][j]) 98 { 99 if((i+j)%2) Link(idx[i][j],t,1); 100 else 101 { 102 Link(s,idx[i][j],1); 103 for(int k=0,t1,t2;k<4;k++) 104 if(Check(t1=i+mov[k][0],t2=j+mov[k][1])) 105 Link(idx[i][j],idx[t1][t2],1); 106 } 107 ava+=mapp[i][j]; 108 } 109 maxx=Dinic_Maxflow(); 110 if(maxx==ava/2&&ava%2==0) printf("0"); 111 else 112 { 113 for(int i=1;i<=n;i++) 114 for(int j=1;j<=m;j++) 115 if(mapp[i][j]&&(i+j)%2==0) Match(idx[i][j]); 116 //for(int i=1;i<=n*m;i++) printf("%d ",mat[i]); 117 for(int i=1;i<=n;i++) 118 for(int j=1;j<=m;j++) 119 if(mapp[i][j]&&!mat[idx[i][j]]) Getans(idx[i][j]); 120 for(int i=1;i<=n;i++) 121 for(int j=1;j<=m;j++) 122 if(ntp[idx[i][j]]) 123 pts++,ans[pts].x=i,ans[pts].y=j; 124 sort(ans+1,ans+1+pts,cmp); 125 printf("%d ",pts); 126 for(int i=1;i<=pts;i++) 127 printf("%d %d ",ans[i].x,ans[i].y); 128 } 129 return 0; 130 }
T3
发现题目实际上不是$k,q<=100000$,是$k*q=sum w<=100000$
分块。对于$k>sqrt m$先在SAM上暴力把串跑一次,记录下每个位置最后的节点在哪,然后变成求每个询问的子串出现次数;对于$k<sqrt m$直接$k^2$枚举所有子串来做。
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define vint vector<int> 6 #define vit vector<int>::iterator 7 using namespace std; 8 const int N=200005,Sq=320,K=20; 9 int n,m,q,k,t1,t2,cnt,lst,tot; 10 int p[N],noww[N],goal[N],ll[N],rr[N]; 11 int trs[N][26],fth[N],siz[N],len[N],anc[N][K]; 12 char str[N],rd[N]; int qlen[N],qpos[N]; 13 vint sub[Sq][Sq]; 14 void Link(int f,int t) 15 { 16 noww[++cnt]=p[f]; 17 goal[cnt]=t,p[f]=cnt; 18 } 19 void Insert(int ch) 20 { 21 int nde=lst,newn=++tot; lst=newn; 22 siz[newn]=1,len[newn]=len[nde]+1; 23 while(nde&&!trs[nde][ch]) 24 trs[nde][ch]=newn,nde=fth[nde]; 25 if(!nde) fth[newn]=1; 26 else 27 { 28 int tran=trs[nde][ch]; 29 if(len[tran]==len[nde]+1) 30 fth[newn]=tran; 31 else 32 { 33 int rnde=++tot; len[rnde]=len[nde]+1; 34 for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i]; 35 fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde; 36 while(nde&&trs[nde][ch]==tran) 37 trs[nde][ch]=rnde,nde=fth[nde]; 38 } 39 } 40 } 41 void DFS(int nde) 42 { 43 anc[nde][0]=fth[nde]; 44 for(int i=1;i<=19;i++) 45 anc[nde][i]=anc[anc[nde][i-1]][i-1]; 46 for(int i=p[nde];i;i=noww[i]) 47 DFS(goal[i]),siz[nde]+=siz[goal[i]]; 48 } 49 void Pre() 50 { 51 lst=tot=1; 52 for(int i=0;i<n;i++) Insert(str[i]-'a'); 53 for(int i=1;i<=tot;i++) Link(fth[i],i); DFS(1); 54 } 55 int Query(vint ve,int ll,int rr) 56 { 57 vit it1=lower_bound(ve.begin(),ve.end(),ll); 58 vit it2=upper_bound(ve.begin(),ve.end(),rr); 59 return it2-it1; 60 } 61 void Solve1() 62 { 63 while(q--) 64 { 65 long long ans=0; 66 scanf("%s%d%d",rd,&t1,&t2); 67 for(int i=0;i<k;i++) 68 { 69 int nde=1; 70 for(int j=i;j<k;j++) 71 { 72 int ch=rd[j]-'a'; 73 if(!trs[nde][ch]) break; 74 nde=trs[nde][ch]; 75 ans+=1ll*siz[nde]*Query(sub[i][j],t1,t2); 76 } 77 } 78 printf("%lld ",ans); 79 } 80 } 81 int Climb(int lth,int nde) 82 { 83 for(int i=19;~i;i--) 84 if(lth<=len[anc[nde][i]]) 85 nde=anc[nde][i]; 86 return siz[nde]; 87 } 88 void Solve2() 89 { 90 while(q--) 91 { 92 int nde=1; long long ans=0; 93 scanf("%s%d%d",rd,&t1,&t2); 94 for(int i=0,lth=0;i<k;i++) 95 { 96 int ch=rd[i]-'a'; 97 while(nde&&!trs[nde][ch]) 98 nde=fth[nde],lth=len[nde]; 99 if(!nde) nde=1,qlen[i]=0; 100 else nde=trs[nde][ch],qlen[i]=++lth; 101 qpos[i]=nde; 102 } 103 for(int i=t1;i<=t2;i++) 104 if(qlen[rr[i]]>=rr[i]-ll[i]+1) 105 ans+=Climb(rr[i]-ll[i]+1,qpos[rr[i]]); 106 printf("%lld ",ans); 107 } 108 } 109 int main() 110 { 111 scanf("%d%d%d%d%s",&n,&m,&q,&k,str); 112 for(int i=0;i<m;i++) 113 { 114 scanf("%d%d",&ll[i],&rr[i]); 115 if(k<=Sq) sub[ll[i]][rr[i]].push_back(i); 116 } 117 Pre(),k<=Sq?Solve1():Solve2(); 118 return 0; 119 }