LOJios
一個暴力\(dp\),設\(f[i][j]\)表示考慮完了前\(i\)個位置,其中最後一個數在前面全部數中排名是第\(j\)大,那麼轉移的時候枚舉一下當前數是第幾大,而且知足不等式的限制就能夠了,而後拿前綴和優化一下就能夠作到\(O(n^2)\)。
咱們把全部連續的<
當作一段,這樣子題目就變成了每次要選出一段連續的上升序列,而後相鄰兩個連續段之間必須知足前一段的末尾要大於後一段的開頭。
顯然這個大於號是很差處理的,若是咱們可以任意就很好作了。
這些>
,即段與段之間的分割的位置的大小狀況,若是至少有\(i\)個隨意,方案數是\(g[i]\),那麼對於答案的貢獻就是\((-1)^ig[i]\)。
再考慮一個\(dp\),咱們假設分割出來的全部段中,第\(i\)段的長度是\(a[i]\)。設\(f[i][j]\)表示考慮完了前\(i\)段,選出了\(j\)個上升序列的方案數,這樣子就至少有\(i-j\)個位置是非法的。轉移的話枚舉把哪一段做爲一段上升序列,那麼就是:
\[f[i][j]=\sum_{k=0}^{i-1}f[k][j-1]*{n-s[k]\choose s[i]-s[k]}\]
其中\(s\)是\(a\)的前綴和。
不難發現第二維用處不大,由於容斥係數只有\(\pm 1\),因此能夠把容斥係數帶進去直接帶進去而不須要額外記錄第二維來輔助計算。
因而轉移就變成了:
\[f[i]=-\sum_{k=0}^{i-1}f[k]{n-s[k]\choose s[i]-s[k]}\]
發現拆開以後能夠卷積,而後有一項是\((s[i]-s[k])!\)不太好弄,由於\(s\)足夠小,因此把\(i\)變到\(s[i]\)位置卷,這樣子\(s[i]-s[k]\)就變成了\(i-k\),那麼對於非\(s[i]\)的位置,把它強制弄成\(0\)。這樣子拿分治\(FFT\)卷一下就行了。優化
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MOD 998244353 #define MAX 524288 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;} int W[MAX],r[MAX]; void NTT(int *P,int opt,int len) { int N,l=0;for(N=1;N<len;N<<=1)++l; for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]); for(int i=1;i<N;i<<=1) { int w=fpow(3,(MOD-1)/(i<<1));W[0]=1; for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD; for(int j=0,p=i<<1;j<N;j+=p) for(int k=0;k<i;++k) { int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD; P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD; } } if(opt==-1) { reverse(&P[1],&P[N]); for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD; } } int jc[MAX],jv[MAX],inv[MAX]; int n,a[MAX],ans,cnt;char s[MAX]; bool book[MAX]; int A[MAX],B[MAX],f[MAX]; void CDQ(int l,int r) { if(l==r) { if(l==0)f[l]=1; else if(!book[l])f[l]=0; else f[l]=1ll*f[l]*(MOD-jv[n-l])%MOD; return; } int mid=(l+r)>>1; CDQ(l,mid); for(int i=l;i<=mid;++i)A[i-l]=1ll*f[i]*jc[n-i]%MOD; for(int i=1;i<=r-l+1;++i)B[i]=jv[i]; int N;for(N=1;N<=r-l+1+mid-l+1;N<<=1); NTT(A,1,N);NTT(B,1,N); for(int i=0;i<N;++i)A[i]=1ll*A[i]*B[i]%MOD; NTT(A,-1,N); for(int i=mid+1;i<=r;++i)f[i]=(f[i]+A[i-l])%MOD; for(int i=0;i<N;++i)A[i]=B[i]=0; CDQ(mid+1,r); } int C(int n,int m){if(n<0||m<0||n<m)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;} int main() { scanf("%s",s+1);n=strlen(s+1)+1; for(int i=1;i<n;++i)if(s[i]=='>')book[i]=true,++cnt; inv[0]=inv[1]=jc[0]=jv[0]=1; for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD; for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD; for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD; CDQ(0,n); /* f[0]=1; for(int i=1;i<=n;++i) if(book[i]) for(int j=0;j<i;++j) f[i]=(f[i]+MOD-1ll*f[j]*C(n-j,i-j)%MOD)%MOD; */ for(int i=0;i<=n;++i)ans=(ans+f[i])%MOD; if(cnt&1)ans=(MOD-ans)%MOD; printf("%d\n",ans); return 0; }