4.12上午 模拟赛
T1 bzoj 2806
题目大意:
给出$n$个字符串表示模式串,$m$次询问,每次给出一个串
对于一个模式串的子串,我们可以将其称为一个好的串
对于一个给出的串,需要将这个串划分为若干段,使得这些段中好的串的总长度不少于总长的$85%$
现在要使这个划分方案中最短的好的串的长度最大,输出这个满足条件的情况下最短串长度的最大值
思路:
很容易想到二分答案,得到$f_i=max(f_j+i-j),j<=i-mid$其中$s[j:i]$为一个加分句
用广义后缀自动机处理出每个点向前最远可以匹配到的位置
这个位置是单调上升的,用单调队列维护一个dp值单调下降的队列即可
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define db double 4 #define inf 2139062143 5 #define MAXN 2001000 6 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 7 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 8 #define ren for(register int i=fst[x];i;i=nxt[i]) 9 #define pls(a,b) (a+b)%MOD 10 #define mns(a,b) (a-b+MOD)%MOD 11 #define mul(a,b) (1LL*(a)*(b))%MOD 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+(ch&15);ch=getchar();} 18 return x*f; 19 } 20 int n,m,mxl[MAXN],pos[MAXN],fa[MAXN],tr[MAXN][2],las=1,tot=1; 21 int len,f[MAXN],q[MAXN],hd,tl; 22 char s[MAXN]; 23 void extend(int c) 24 { 25 int p=las,np=las=++tot;mxl[np]=mxl[p]+1; 26 for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=np; 27 if(!p) {fa[np]=1;return ;}int q=tr[p][c]; 28 if(mxl[q]==mxl[p]+1) {fa[np]=q;return ;} 29 int nq=++tot;mxl[nq]=mxl[p]+1; 30 memcpy(tr[nq],tr[q],sizeof(tr[nq])); 31 fa[nq]=fa[q],fa[q]=fa[np]=nq; 32 for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq; 33 } 34 int X(int x) {return f[x]-x;} 35 int cheq(int x) 36 { 37 hd=1,tl=0;rep(i,1,len) 38 { 39 f[i]=f[i-1];if(i<x) continue; 40 while(hd<=tl&&X(q[tl])<=X(i-x)) tl--;q[++tl]=i-x; 41 while(hd<=tl&&q[hd]<i-pos[i]) hd++; 42 if(hd<=tl) f[i]=max(f[i],f[q[hd]]+i-q[hd]); 43 } 44 return f[len]*20>=len*17; 45 } 46 int main() 47 { 48 n=read(),m=read();rep(i,1,m) 49 { 50 scanf("%s",s+1);len=strlen(s+1); 51 las=1;rep(i,1,len) extend(s[i]-'a'); 52 } 53 int p,c,res,l,r,mid,ans;rep(i,1,n) 54 { 55 scanf("%s",s+1);len=strlen(s+1),p=1,res=0; 56 rep(i,1,len) 57 { 58 c=s[i]-'a';if(tr[p][c]) {pos[i]=++res,p=tr[p][c];continue;} 59 for(;p&&!tr[p][c];p=fa[p]); 60 if(!p) pos[i]=res=0,p=1;else pos[i]=res=mxl[p]+1,p=tr[p][c]; 61 } 62 for(l=ans=0,r=len;mid=l+r>>1,l<=r;) 63 if(cheq(mid)) ans=mid,l=mid+1;else r=mid-1; 64 printf("%d\n",ans); 65 } 66 }
T2 bzoj 4657
题目大意:
一个网格图,有一些发射点可以发射单向的射线,保证不会有发射点在别的点的线上,除了发射点每个点有一个权值
每个发射点可以在射线上取一个点,拿到这个点的权值,需要在保证这些发射点与选的点不相交的情况下,使取的点权值和最大
思路:
先假设每个发射点都取到了它能取到的最大值
使用最小割来满足不相交的条件,因为每个点最多被两个分别为横竖的发射点所覆盖
每个点拆成两个点,其中一个向另一个连$inf$的边表示不能被割
每个点发射出去的射线连成一条链,每个边的权值是最大值-这个点的权值,表示割边=选这个点
然后用总答案去减即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 5010 15 #define MAXM 20100 16 #define MOD 998244353 17 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 18 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 19 #define ren for(register int i=fst[x];i;i=nxt[i]) 20 #define pls(a,b) (a+b)%MOD 21 #define mns(a,b) (a-b+MOD)%MOD 22 #define mul(a,b) (1LL*(a)*(b))%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+(ch&15);ch=getchar();} 29 return x*f; 30 } 31 int n,m,mp[55][55],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0}; 32 struct Dinic 33 { 34 int fst[MAXN],nxt[MAXM<<1],to[MAXM<<1],cnt,val[MAXM<<1]; 35 int vis[MAXN],q[MAXN],l,r,S,T,tot,dis[MAXN],cur[MAXN]; 36 Dinic(){memset(fst,0,sizeof(fst));cnt=1,tot=0;} 37 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;} 38 void ins(int u,int v,int w) {add(u,v,w);add(v,u,0);} 39 int bfs() 40 { 41 vis[T]=++tot,dis[T]=0,q[l=r=1]=T;int x; 42 while(l<=r) 43 { 44 x=q[l++],cur[x]=fst[x];ren if(val[i^1]&&vis[to[i]]!=tot) 45 dis[to[i]]=dis[x]+1,vis[to[i]]=tot,q[++r]=to[i]; 46 } 47 return vis[S]==tot; 48 } 49 int dfs(int x,int a) 50 { 51 if(x==T||!a) return a;int flw=0,f; 52 for(int& i=cur[x];i&&a;i=nxt[i]) 53 if(val[i]&&dis[to[i]]==dis[x]-1&&(f=dfs(to[i],min(a,val[i])))) 54 val[i]-=f,val[i^1]+=f,a-=f,flw+=f; 55 return flw; 56 } 57 int solve(int ss,int tt,int res=0) 58 {S=ss,T=tt;while(bfs()) res+=dfs(S,inf);return res;} 59 }D; 60 int t(int x,int y,int w) {return (x-1)*m+y-1+w*n*m;} 61 int ok(int x,int y) {return x&&y&&x<=n&&y<=m;} 62 #define nx tx+dx[k] 63 #define ny ty+dy[k] 64 int main() 65 { 66 n=read(),m=read();int ss=2*n*m+1,tt=ss+1,k,tx,ty,mx,sum=0,tag; 67 rep(i,1,n) rep(j,1,m) mp[i][j]=read(); 68 rep(i,1,n) rep(j,1,m) if(mp[i][j]>=0) D.ins(t(i,j,0),t(i,j,1),inf); 69 else 70 { 71 (tag=(mp[i][j]>=-2))?D.ins(ss,t(i,j,0),inf):D.ins(t(i,j,1),tt,inf); 72 for(k=4+mp[i][j],mx=0,tx=i,ty=j;tx=nx,ty=ny,ok(tx,ty);) 73 mx=max(mx,mp[tx][ty]);sum+=mx; 74 for(k=4+mp[i][j],tx=i,ty=j;ok(nx,ny);tx=nx,ty=ny) 75 if(tag) D.ins(t(tx,ty,0),t(nx,ny,0),mx-max(mp[tx][ty],0)); 76 else D.ins(t(nx,ny,1),t(tx,ty,1),mx-max(mp[tx][ty],0)); 77 } 78 printf("%d\n",sum-D.solve(ss,tt)); 79 }
T3 Codeforces 960G
题目大意:
给出$n,a,b$ 问$n$的排列中,前缀最大值有$a$种,后缀最大值有$b$种的排列有多少个
思路:
很明显$n$这个数成为一个分界点
对于前面的数, 每个最大值到下一个最大值之前的这段区间可以看做是一个环,把最大的数放在了第一个,后面同理
这样相当于第一类斯特林数,将$n-1$个数分成$a+b-2$个环,再选出$a-1$个放在前面
只需要求出整行的第一类斯特林数即可
$s1(n,k)$为$\prod\limits_{i=0}^{n-1} (x+i)$的$k$次项系数
分治+$fft$即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 100100 15 #define MOD 998244353 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pls(a,b) (a+b)%MOD 20 #define mns(a,b) (a-b+MOD)%MOD 21 #define mul(a,b) (1LL*(a)*(b))%MOD 22 #define pb(a) push_back(a) 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+(ch&15);ch=getchar();} 29 return x*f; 30 } 31 int n,a,b,fac[MAXN<<1],ifac[MAXN<<1],l2[MAXN<<2],pw[30],ipw[30]; 32 int A[MAXN<<2],B[MAXN<<2],rev[MAXN<<2]; 33 int C(int n,int m) {return mul(mul(fac[n],ifac[m]),ifac[n-m]);} 34 vector<int> vec[MAXN]; 35 int q_pow(int bas,int t,int res=1) 36 { 37 for(;t;bas=mul(bas,bas),t>>=1) 38 if(t&1) res=mul(res,bas);return res; 39 } 40 void ntt(int *a,int n,int f) 41 { 42 rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]); 43 for(int i=1;i<n;i<<=1) 44 { 45 int wn=f>0?pw[l2[i]+1]:ipw[l2[i]+1]; 46 for(int j=0;j<n;j+=i<<1) 47 { 48 for(int k=0,w=1,x,y;k<i;k++,w=mul(w,wn)) 49 x=a[k+j],y=mul(a[i+j+k],w),a[j+k]=pls(x,y),a[i+j+k]=mns(x,y); 50 } 51 } 52 if(f==1) return ;int nv=q_pow(n,MOD-2); 53 rep(i,0,n-1) a[i]=mul(a[i],nv); 54 } 55 void solve(int *a,int *b,int lmt) 56 { 57 ntt(a,lmt,1);ntt(b,lmt,1);rep(i,0,lmt-1) a[i]=mul(a[i],b[i]); 58 ntt(a,lmt,-1); 59 } 60 void Div(int l,int r,ll lmt=0) 61 { 62 if(l==r) return ;int mid=(l+r)>>1,lg; 63 Div(l,mid);Div(mid+1,r);lg=l2[r-l+1]+1,lmt=1<<lg; 64 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),A[i]=B[i]=0; 65 rep(i,0,vec[l].size()-1) A[i]=vec[l][i]; 66 rep(i,0,vec[mid+1].size()-1) B[i]=vec[mid+1][i]; 67 solve(A,B,lmt);vec[l].clear();vec[mid+1].clear(); 68 rep(i,0,lmt-1) vec[l].pb(A[i]); 69 } 70 int main() 71 { 72 n=read(),a=read(),b=read();fac[0]=ifac[0]=fac[1]=ifac[1]=1; 73 if(n==1) return putchar((a==1&&b==1)?'1':'0'),0; 74 rep(i,2,n<<1) fac[i]=mul(fac[i-1],i),ifac[i]=mul(MOD-MOD/i,ifac[MOD%i]); 75 rep(i,2,n) ifac[i]=mul(ifac[i],ifac[i-1]);l2[0]=-1;rep(i,1,n<<2) 76 { 77 l2[i]=l2[i>>1]+1;if(!pw[l2[i]]) 78 pw[l2[i]]=q_pow(3,(MOD-1)/i),ipw[l2[i]]=q_pow(pw[l2[i]],MOD-2); 79 } 80 rep(i,0,n-2) vec[i].pb(i),vec[i].pb(1);Div(0,n-2); 81 if(a+b-2>n-1) return putchar('0'),0; 82 printf("%d\n",mul(vec[0][a+b-2],C(a+b-2,a-1))); 83 }