RT
Part1
决策单调性优化DP,设$dp[i][j]$表示前$i$个数分成$j$段的最小代价,转移是$dp[i][j]=min(dp[i][j],dp[k][j-1]+rev(k+1,i))$,暴力移动指针求区间逆序对。因为后面那坨东西并不是单峰的所以用分治解决
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=40005,inf=2e9; 6 int a[N],b[N],dp[N],tmp[N]; 7 int n,m,lp,rp,ans; 8 void Add(int x,int y) 9 { 10 while(x<=n) 11 b[x]+=y,x+=x&-x; 12 } 13 int Query(int x) 14 { 15 int ret=0; 16 while(x) 17 ret+=b[x],x-=x&-x; 18 return ret; 19 } 20 void Move(int l,int r) 21 { 22 while(lp<l) Add(a[lp],-1),ans-=Query(a[lp++]-1); 23 while(lp>l) Add(a[--lp],1),ans+=Query(a[lp]-1); 24 while(rp>r) Add(a[rp],-1),ans-=rp-lp-Query(a[rp]),rp--; 25 while(rp<r) Add(a[++rp],1),ans+=rp-lp+1-Query(a[rp]); 26 } 27 void Solve(int l,int r,int ll,int rr) 28 { 29 if(l>r) return; 30 int mid=(l+r)>>1,mini=inf,pts=ll; 31 for(int i=ll;i<=min(rr,mid-1);i++) 32 { 33 Move(i+1,mid); 34 if(dp[i]+ans<mini) 35 mini=dp[i]+ans,pts=i; 36 } 37 tmp[mid]=mini; 38 Solve(l,mid-1,ll,pts); 39 Solve(mid+1,r,pts,rr); 40 } 41 int main() 42 { 43 scanf("%d%d",&n,&m),lp=1,rp=0; 44 for(int i=1;i<=n;i++) 45 scanf("%d",&a[i]); 46 for(int i=1;i<=n;i++) 47 Move(1,i),dp[i]=ans; 48 for(int i=2;i<=m;i++) 49 { 50 Solve(1,n,1,n); 51 for(int j=1;j<=n;j++) dp[j]=tmp[j]; 52 } 53 printf("%d",dp[n]); 54 return 0; 55 } 56
求若干数量的球成为答案的期望和某种颜色的球成为答案的概率
主要是学一学形如$f[i]=p*f[i-1]+q*f[i+1]$这种东西怎么做:要求两边能搞出来,从一边开始带着推,推导另一边得解,最后再倒着代回来
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=10005; 6 char str[N]; int cnt[N]; 7 double ans,tr[N],dp[N],k[N],b[N]; 8 int main() 9 { 10 scanf("%s",str+1); 11 int n=strlen(str+1); 12 for(int i=1;i<=n;i++) 13 cnt[str[i]-'A']++; 14 for(int i=1;i<n;i++) 15 tr[i]=1.0*n*(n-1)/2/i/(n-i); 16 dp[n]=0,k[1]=1,b[1]=tr[1]; 17 for(int i=2;i<n;i++) 18 { 19 b[i]=b[i-1]*(i-1)/i/2+tr[i]; 20 k[i]=1.0*(i+1)/i/2; 21 k[i]=k[i]/(1-k[i-1]*(i-1)/i/2); 22 b[i]=b[i]/(1-k[i-1]*(i-1)/i/2); 23 } 24 for(int i=n-1;i;i--) 25 dp[i]=dp[i+1]*k[i]+b[i]; 26 for(int i=0;i<=25;i++) 27 ans+=dp[cnt[i]]*cnt[i]/n; 28 printf("%.1f",ans); 29 return 0; 30 }
题很好 咕咕咕(yda 咕的Blog
发现答案和序列具体长什么样没有什么关系,我们只关心序列长度,于是递推
1 #include<map> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 #define vint vector<int> 7 using namespace std; 8 const int N=100005,mod=1e9+7; 9 int T,op,rd,fac[N],inv[N],pw1[N],pw2[N],iv1[N]; 10 char str[N]; map<int,vint> mp; 11 12 template<class Type> void exGCD(Type a,Type b,Type &x,Type &y) 13 { 14 if(!b) {x=1,y=0; return;} 15 else exGCD(b,a%b,y,x),y-=a/b*x; 16 } 17 18 int Inv(int x) 19 { 20 int xx,yy; 21 exGCD(x,mod,xx,yy); 22 return (xx%mod+mod)%mod; 23 } 24 void Pre(int Maxx) 25 { 26 fac[0]=inv[0]=pw1[0]=pw2[0]=iv1[0]=1; 27 for(int i=1;i<=Maxx;i++) fac[i]=1ll*fac[i-1]*i%mod; 28 inv[Maxx]=Inv(fac[Maxx]); 29 for(int i=Maxx-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; 30 for(int i=1;i<=Maxx;i++) pw1[i]=1ll*pw1[i-1]*26%mod; 31 for(int i=1;i<=Maxx;i++) pw2[i]=1ll*pw2[i-1]*25%mod; 32 int i26=Inv(26); 33 for(int i=1;i<=Maxx;i++) iv1[i]=1ll*iv1[i-1]*i26%mod; 34 } 35 void Solve(vint &v,int n) 36 { 37 v.resize(100001); 38 for(int i=n;i<=100000;i++) 39 v[i]=(v[i-1]+1ll*fac[i-1]*iv1[i]%mod*pw2[i-n]%mod*inv[i-n]%mod)%mod; 40 } 41 int Query(int n,int m) 42 { 43 if(n>m) return 0; 44 return 1ll*mp[n][m]*pw1[m]%mod*inv[n-1]%mod; 45 } 46 int main() 47 { 48 scanf("%d%s",&T,str+1),Pre(100000); 49 int len=strlen(str+1); 50 Solve(mp[len],len); 51 while(T--) 52 { 53 scanf("%d",&op); 54 if(op==1) 55 { 56 scanf("%s",str+1),len=strlen(str+1); 57 if(!mp.count(len)) Solve(mp[len],len); 58 } 59 else 60 scanf("%d",&rd),printf("%d ",Query(len,rd)); 61 } 62 return 0; 63 }
字符串菜鸡终于把这道i207M早就讲了的题A掉了
SAM上跑线段树合并
注意合并要新建点,因为原来的点还要用
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1e6+50,M=9e6+60; 6 7 int trs[N][26],fth[N],siz[N]; 8 int len[N],endp[N],ende[N]; 9 int lth,lng,tot,lst; 10 char str[N],rd[N]; 11 12 int root[N],val[M],vid[M],son[M][2]; 13 int T,n,id,t1,t2,t3,t4,ans,anss; 14 15 int cnt,p[N],noww[N],goal[N],anc[N][20]; 16 17 int Insert(int ch) 18 { 19 int nde=lst,newn=++tot; lst=newn; 20 siz[newn]=1,len[newn]=len[nde]+1; 21 while(nde&&!trs[nde][ch]) 22 trs[nde][ch]=newn,nde=fth[nde]; 23 if(!nde) fth[newn]=1; 24 else 25 { 26 int tran=trs[nde][ch]; 27 if(len[tran]==len[nde]+1) 28 fth[newn]=tran; 29 else 30 { 31 int rnde=++tot; len[rnde]=len[nde]+1; 32 for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i]; 33 fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde; 34 while(nde&&trs[nde][ch]==tran) 35 trs[nde][ch]=rnde,nde=fth[nde]; 36 } 37 } 38 return newn; 39 } 40 41 void Pushup(int nde) 42 { 43 int ls=son[nde][0],rs=son[nde][1]; 44 if(val[ls]>=val[rs]) val[nde]=val[ls],vid[nde]=vid[ls]; 45 else val[nde]=val[rs],vid[nde]=vid[rs]; 46 } 47 void Add(int &nde,int l,int r,int pos,int tsk) 48 { 49 if(!nde) nde=++id; 50 if(l==r) 51 val[nde]+=tsk,vid[nde]=l; 52 else 53 { 54 int mid=(l+r)>>1; 55 if(pos<=mid) Add(son[nde][0],l,mid,pos,tsk); 56 else Add(son[nde][1],mid+1,r,pos,tsk); Pushup(nde); 57 } 58 } 59 int Merge(int x,int y,int l,int r) 60 { 61 if(!x||!y) return x+y; 62 if(l==r) 63 { 64 val[x]=val[x]+val[y],vid[x]=l; 65 return x; 66 } 67 else 68 { 69 int mid=(l+r)>>1; 70 son[x][0]=Merge(son[x][0],son[y][0],l,mid); 71 son[x][1]=Merge(son[x][1],son[y][1],mid+1,r); 72 Pushup(x); return x; 73 } 74 } 75 void Query(int nde,int l,int r,int ll,int rr) 76 { 77 if(!nde) return; 78 if(l>=ll&&r<=rr) 79 { 80 if(ans<val[nde]||(ans==val[nde]&&anss>vid[nde])) 81 ans=val[nde],anss=vid[nde]; 82 } 83 else 84 { 85 int mid=(l+r)>>1; 86 if(mid>=ll) Query(son[nde][0],l,mid,ll,rr); 87 if(mid<rr) Query(son[nde][1],mid+1,r,ll,rr); 88 } 89 } 90 91 void Link(int f,int t) 92 { 93 noww[++cnt]=p[f]; 94 goal[cnt]=t,p[f]=cnt; 95 } 96 void DFS(int nde) 97 { 98 anc[nde][0]=fth[nde]; 99 for(int i=1;i<=19&&anc[nde][i-1];i++) 100 anc[nde][i]=anc[anc[nde][i-1]][i-1]; 101 for(int i=p[nde];i;i=noww[i]) 102 DFS(goal[i]),root[nde]=Merge(root[nde],root[goal[i]],1,n);// printf("%d-=-",val[root[nde]]); 103 } 104 105 int main() 106 { 107 scanf("%s%d",str+1,&n); 108 lth=strlen(str+1),val[0]=-1,tot=1; 109 for(int i=1;i<=n;i++) 110 { 111 scanf("%s",rd+1); 112 lng=strlen(rd+1),lst=1; 113 for(int j=1;j<=lng;j++) 114 { 115 int newn=Insert(rd[j]-'a'); 116 Add(root[newn],1,n,i,1); 117 } 118 } 119 int nde=1,mxl=0; 120 for(int i=1;i<=lth;i++) 121 { 122 int ch=str[i]-'a'; 123 while(nde&&!trs[nde][ch]) 124 nde=fth[nde],mxl=len[nde]; 125 if(nde) nde=trs[nde][ch],mxl++; 126 else nde=1,mxl=0; 127 endp[i]=nde,ende[i]=mxl; 128 } 129 for(int i=1;i<=tot;i++) Link(fth[i],i); DFS(1); 130 // for(int i=1;i<=id;i++) 131 // printf("%d %d ",val[i],vid[i]); 132 scanf("%d",&T); 133 while(T--) 134 { 135 scanf("%d%d%d%d",&t1,&t2,&t3,&t4); 136 nde=endp[t4],mxl=t4-t3+1; 137 if(ende[t4]<mxl) 138 printf("%d 0 ",t1); 139 else 140 { 141 for(int i=19;~i;i--) 142 if(len[anc[nde][i]]>=mxl) 143 nde=anc[nde][i]; 144 ans=-1,anss=1e9; 145 Query(root[nde],1,n,t1,t2); 146 ~ans?printf("%d %d ",anss,ans):printf("%d 0 ",t1); 147 } 148 } 149 return 0; 150 }
Part 2
肥肠爆芡,这块整体咕咕了
一定补一定补