先将这个序列翻转,贪心找到最长的'101010……'的形式的子序列并删除,重复此过程并记这些字符串长度依次为$l_{1},l_{2},...,l_{n}$,若最终还有字符剩余则一定无解
假设$S$中元素从大到小依次为$x_{1},x_{2},...,x_{m}$,则合法当且仅当:
1.$L=sum_{i=1}^{n}l_{i}=sum_{i=1}^{m}x_{i}$
2.$forall 1le ile n,sum_{j=1}^{i}lfloor frac{l_{j}}{2} floorge sum_{j=1}^{i}lfloor frac{x_{j}}{2} floor$(可以证明$nle m$)
3.$forall 1le ile n,sum_{j=1}^{i}lceil frac{l_{j}}{2} ceilge sum_{j=1}^{i}lceil frac{x_{j}}{2} ceil$
考虑必要性,第一个条件是因为$x_{i}$必然操作$x_{i}$次从而产生长为$x_{i}$的串,而$sum_{i=1}^{n}l_{i}$即为序列长度(有剩余字符无解),因此相等
对于第2和3个限制(以2为例),每一个$x_{i}$产生了一个长度为$x_{i}$的'101010……'的序列,以此为$l_{i}$则恰好满足,那么选择最长的'101010……'前缀和一定不会变小,因此满足该条件
充分性的证明过程可以看原题解后半部分:
考虑dp,令$f[i][j][k][l]$表示有多少种$x_{1},x_{2},...,x_{i}$满足$sum_{t=1}^{i}lfloor frac{x_{t}}{2} floor=j$且$sum_{t=1}^{i}lceil frac{x_{t}}{2} ceil=k$且$x_{i}=l$,这样转移复杂度为$o(L^{5})$,最终答案即$sum_{i=n}^{L}sum_{l=1}^{L}f[i][sum_{j=1}^{n}lfloorfrac{l_{j}}{2} floor][sum_{k=1}^{n}lceilfrac{l_{k}}{2} ceil][l]$
由于$x_{1}ge x_{2}ge ...ge x_{i}$,而$sum_{j=1}^{i}x_{i}le L$,因此$lle frac{L}{i}$,再通过前缀和可以优化到$o(L^{3}ln L)$,空间上通过对第一维滚动可以做到$o(L^{3})$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 305 4 #define mod 1000000007 5 int n,m,ans,a[N],s1[N],s2[N],f[2][N][N][N]; 6 char s[N]; 7 int main(){ 8 scanf("%s",s); 9 int l=m=strlen(s); 10 for(int i=0;i<l/2;i++)swap(s[i],s[l-i-1]); 11 while (l){ 12 if (s[0]=='0'){ 13 printf("0"); 14 return 0; 15 } 16 int p=1,ll=l; 17 n++; 18 l=0; 19 for(int i=0;i<ll;i++) 20 if (s[i]-'0'!=p)s[l++]=s[i]; 21 else{ 22 a[n]++; 23 p^=1; 24 } 25 } 26 for(int i=1;i<=m;i++)s1[i]=s1[i-1]+a[i]/2; 27 for(int i=1;i<=m;i++)s2[i]=s2[i-1]+(a[i]+1)/2; 28 f[0][0][0][m]=1; 29 for(int i=0,p=1;i<m;i++,p^=1){ 30 for(int j=0;j<=s1[i+1];j++) 31 for(int k=0;k<=s2[i+1];k++) 32 for(int l=1;l<=m/max(i-1,1);l++)f[p][j][k][l]=0; 33 for(int j=0;j<=s1[i];j++) 34 for(int k=0;k<=s2[i];k++){ 35 for(int l=m/max(i,1)-1;l;l--) 36 f[p^1][j][k][l]=(f[p^1][j][k][l]+f[p^1][j][k][l+1])%mod; 37 for(int l=1;l<=m/(i+1);l++) 38 if ((j+l/2<=s1[i+1])&&(k+(l+1)/2<=s2[i+1])) 39 f[p][j+l/2][k+(l+1)/2][l]=(f[p][j+l/2][k+(l+1)/2][l]+f[p^1][j][k][l])%mod; 40 } 41 if (i>=n-1) 42 for(int j=1;j<=m;j++)ans=(ans+f[p][s1[n]][s2[n]][j])%mod; 43 } 44 printf("%d",ans); 45 }