调T3沙茶错误调半天,最后T1没写暴力,0+100+90滚粗了
T1
如果玩一玩/推一推可以发现两段前缀相同的序列p1和p2 构成的方案数是$Catalan(|p1|,|p2|)$,于是预处理从每对位置$a,b$开始的最长相同长度,然后就可以DP了:设$dp[i][j]$表示第一个序列从$i$第二个序列从$j$开始数的方案数
转移1:两个位置不相同,直接$dp[i][j]+=dp[i+1][j]+dp[i][j+1]$
转移2:两个位置相同,枚举两个序列向后延伸的长度转移,具体看代码
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=2005,M=4005,mod=998244353; 6 int n,a[N],b[N],fac[M],inv[M],lst[N][N],dp[N][N]; 7 void Inc(int &x,int y) 8 { 9 x+=y; 10 if(x>=mod) x-=mod; 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 template<class Type> Type Inv(Type x) 18 { 19 Type xx,yy; 20 exGCD(x,mod,xx,yy); 21 return (xx%mod+mod)%mod; 22 } 23 void Getfac(int Maxx) 24 { 25 fac[0]=inv[0]=1; 26 for(int i=1;i<=Maxx;i++) fac[i]=1ll*fac[i-1]*i%mod; 27 inv[Maxx]=Inv(fac[Maxx]); 28 for(int i=Maxx-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; 29 } 30 int C(int a,int b) 31 { 32 return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod; 33 } 34 int Cat(int a,int b) 35 { 36 return (C(a+b,b)-C(a+b,b-1)+mod)%mod; 37 } 38 int DFS(int l1,int l2) 39 { 40 if(~dp[l1][l2]) return dp[l1][l2]; 41 if(l1>n||l2>n) return dp[l1][l2]=1; 42 int ret=0; 43 if(a[l1]!=b[l2]) 44 ret=(DFS(l1+1,l2)+DFS(l1,l2+1))%mod; 45 else 46 { 47 int len=lst[l1][l2]; 48 ret=1ll*Cat(len,len)*DFS(l1+len,l2+len)%mod; 49 for(int i=1;i<=len;i++) 50 { 51 int len1=l1+len+i-1,len2=l2+len+i-1; 52 if(len1>n&&len2>n) break; 53 if(len1<=n) Inc(ret,1ll*Cat(len+i,len-i)*DFS(l1+len+i,l2+len-i)%mod); 54 if(len2<=n) Inc(ret,1ll*Cat(len+i,len-i)*DFS(l1+len-i,l2+len+i)%mod); 55 } 56 } 57 return dp[l1][l2]=ret; 58 } 59 int main() 60 { 61 scanf("%d",&n); 62 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 63 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 64 for(int i=n;i;i--) 65 for(int j=n;j;j--) 66 if(a[i]==b[j]) lst[i][j]=lst[i+1][j+1]+1; 67 Getfac(2*n),memset(dp,-1,sizeof dp),printf("%d",DFS(1,1)); 68 return 0; 69 }
T2
这题考了***三遍了
T3
线段树上奇怪操作一定要考虑加上限制的暴力是不是就是对的
考场上写的如果区间都一样统一修改,然后被卡了(随机0/1序列,每次整个区间加/减(x-1)再除以x)
正解是如果 原最大值-新最大值=原最小值-新最小值 就修改,正确性是因为这时最大值和最小值相差不超过1,复杂度我放题解了
1 #pragma GCC optimize(2) 2 #include<cmath> 3 #include<cstdio> 4 #include<cctype> 5 #include<cstring> 6 #include<algorithm> 7 #include<iostream> 8 using namespace std; 9 const int N=400005,inf=2e9; 10 int a[N],mini[N],maxx[N],laz[N]; 11 int n,m,op,t1,t2,t3; long long sum[N]; 12 13 char BF[1<<23],*P1=BF,*P2=BF; 14 char Gc(){return (P1==P2&&(P2=(P1=BF)+fread(BF,1,1<<21,stdin),P1==P2)?EOF:*P1++);} 15 template<class Type> void Fread(Type &x)//fread 16 { 17 x=0; int lw=false; 18 char ch=Gc(); 19 while(!isdigit(ch)) 20 lw|=ch=='-',ch=Gc(); 21 while(isdigit(ch)) 22 x=(x<<1)+(x<<3)+(ch^48),ch=Gc(); 23 if(lw) x=-x; 24 } 25 char OBF[1<<23],*Ot=OBF; 26 template<class Type> void W2(Type x) 27 { 28 if(x>9) W2(x/10); 29 *Ot++=x%10|48; 30 } 31 template<class Type> void Fwrite(Type x)//fwrite 32 { 33 if(x<0) *Ot++='-',x=-x; 34 W2(x),*Ot++=' '; 35 } 36 37 bool Ava(int x,int y) 38 { 39 return maxx[x]-floor((double)maxx[x]/y)==mini[x]-floor((double)mini[x]/y); 40 } 41 void Pushup(int nde) 42 { 43 int ls=nde*2,rs=nde*2+1; 44 sum[nde]=sum[ls]+sum[rs]; 45 mini[nde]=min(mini[ls],mini[rs]); 46 maxx[nde]=max(maxx[ls],maxx[rs]); 47 } 48 void Create(int nde,int l,int r) 49 { 50 if(l==r) 51 sum[nde]=mini[nde]=maxx[nde]=a[l]; 52 else 53 { 54 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1; 55 Create(ls,l,mid),Create(rs,mid+1,r),Pushup(nde); 56 } 57 } 58 void Release(int nde,int l,int r) 59 { 60 if(laz[nde]) 61 { 62 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1,&lz=laz[nde]; 63 laz[ls]+=lz,laz[rs]+=lz; 64 mini[ls]+=lz,mini[rs]+=lz; 65 maxx[ls]+=lz,maxx[rs]+=lz; 66 sum[ls]+=1ll*lz*(mid-l+1),sum[rs]+=1ll*lz*(r-mid),lz=0; 67 } 68 } 69 void Add(int nde,int l,int r,int ll,int rr,int tsk) 70 { 71 if(l>rr||r<ll) 72 return ; 73 else if(l>=ll&&r<=rr) 74 sum[nde]+=1ll*tsk*(r-l+1),mini[nde]+=tsk,maxx[nde]+=tsk,laz[nde]+=tsk; 75 else 76 { 77 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1; Release(nde,l,r); 78 Add(ls,l,mid,ll,rr,tsk),Add(rs,mid+1,r,ll,rr,tsk),Pushup(nde); 79 } 80 } 81 void Change(int nde,int l,int r,int ll,int rr,int tsk) 82 { 83 if(l>rr||r<ll) 84 return; 85 else if(l>=ll&&r<=rr&&Ava(nde,tsk)) 86 { 87 int task=floor((double)maxx[nde]/tsk)-maxx[nde]; 88 sum[nde]+=1ll*task*(r-l+1),mini[nde]+=task,maxx[nde]+=task,laz[nde]+=task; 89 } 90 else 91 { 92 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1; Release(nde,l,r); 93 Change(ls,l,mid,ll,rr,tsk); 94 Change(rs,mid+1,r,ll,rr,tsk); Pushup(nde); 95 } 96 } 97 long long Query_sum(int nde,int l,int r,int ll,int rr) 98 { 99 if(l>rr||r<ll) 100 return 0; 101 else if(l>=ll&&r<=rr) 102 return sum[nde]; 103 else 104 { 105 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1; Release(nde,l,r); 106 return Query_sum(ls,l,mid,ll,rr)+Query_sum(rs,mid+1,r,ll,rr); 107 } 108 } 109 int Query_min(int nde,int l,int r,int ll,int rr) 110 { 111 if(l>rr||r<ll) 112 return inf; 113 else if(l>=ll&&r<=rr) 114 return mini[nde]; 115 else 116 { 117 int mid=(l+r)>>1,ls=2*nde,rs=2*nde+1; Release(nde,l,r); 118 return min(Query_min(ls,l,mid,ll,rr),Query_min(rs,mid+1,r,ll,rr)); 119 } 120 } 121 int main() 122 { 123 register int i; 124 Fread(n),Fread(m); 125 for(i=1;i<=n;i++) Fread(a[i]); 126 Create(1,1,n); 127 for(i=1;i<=m;i++) 128 { 129 Fread(op),Fread(t1),Fread(t2); 130 if(op==1) Fread(t3),Add(1,1,n,t1,t2,t3); 131 else if(op==2) Fread(t3),Change(1,1,n,t1,t2,t3); 132 else if(op==3) Fwrite(Query_min(1,1,n,t1,t2)); 133 else Fwrite(Query_sum(1,1,n,t1,t2)); 134 } 135 fwrite(OBF,Ot-OBF,1,stdout); 136 return 0; 137 }