对于一个字符串$s$,考虑构造一个等价的序列$a_{i}$,使得可以通过$a_{i}$来判定$s$是否合法
由于当一个w被改变后不会再变回来,因此可以把w的地方断开,分为若干段,两个段是独立的,即变为了若干个仅含有r和b的段
对于每一个段,令$a_{i}$为其中b的段数+1(序列$a_{i}$的长度即为总段数),其具有以下性质:
1.不存在长度小于$a_{i}$的操作序列可以得到该段
2.长为$a_{i}$的操作序列合法当且仅当以rb(若$a_{i}=1$则必须为r)开头
对于性质1,每一次操作至多让b的段数增加1,同时第1次操作无法增加,因此至少需要$a_{i}$次操作
对于性质2,首先$a_{i}le 2$时成立,然后归纳,对于新加入的一段b,如果新加入的操作是b直接覆盖即可,否则令上一次b操作的范围增大,用r将其断开即可
然后如果不以rb开头,那么前两次操作不能使b的段数为1,类似结论1可得其无解
根据这两个结论,$a_{i}$符合我们构造的条件,考虑枚举$a_{i}$,枚举方法如下:
由于$a_{i}$为段数+1,因此该段长度$le max(2a_{i}-3,1)$,将所有段累加,又因为至少存在$m-1$个w的空隙($m$为段数),总长不超过$n$,即$sum_{i=1}^{m}max(2a_{i}-3,1)+m-1le n$
令$a'_{i}=max(a_{i},2)-1$,有$max(2a_{i}-3,1)=2a'_{i}-1$,代入化简可得$sum_{i=1}^{m}a'_{i}le lfloorfrac{n+1}{2} floor$
当$n=70$,$a'_{i}$的方案数为81156种,再枚举$a_{i}=1$的数字个数,总共有418662种(计算代码如下)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 105 4 int n,ans,f[N][N]; 5 int main(){ 6 n=35; 7 f[0][0]=1; 8 for(int i=1;i<=n;i++) 9 for(int j=1;j<=i;j++)f[i][j]=f[i-j][min(i-j,j)]+f[i][j-1]; 10 for(int i=1;i<=n;i++)f[i][i]+=f[i-1][i-1]; 11 for(int i=0;i<=n;i++)ans+=f[i][i]; 12 printf("%d",ans); 13 }
对于一个$a_{i}$,我们要做两件事情:1.判定其是否合法;2.求出其对应的$s$数量
判定合法:贪心,优先操作$a_{i}$较大的,不断找到下一个r和b,随便统计一下即可
求方案数:先确定$a_{i}$的顺序,即将$a_{i}$打乱后不同的序列数,有$frac{m!}{prod_{i}(sum_{j=1}^{n}[a_{j}=i])!}$种
将$s$的连续段缩为1个字母(记作$s'$),那么$s'$必然包含一个长为$l_{1}=2sum_{i=1}^{m}a'_{i}-1$的子序列(即尽量短的方案),同时自身也是一个长为$l_{2}=2sum_{i=1}^{m}a_{i}+1$的序列的子序列(即$l_{1}$补上两端的r和w)
一个例子:对于$a_{i}={2,1,3}$,$l_{1}$为bwrwbrb,$l_{2}$为**wr**b**r**wrw**r**brb**rw**(其中加粗的为补上的r和w)
然后$s$可以看作插板法划分为$l_{2}$段,其中有$l_{2}-l_{1}$段可以为空,即有$n+(l_{2}-l_{1})-1choose l_{2}-1$种
总时间复杂度为$o(418662n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 205 4 #define mod 1000000007 5 pair<int,int>pos[N]; 6 int n,k,ans,a[N],sum[N],fac[N],inv[N]; 7 char s[N]; 8 void init(){ 9 fac[0]=inv[0]=inv[1]=1; 10 for(int i=1;i<N-4;i++)fac[i]=1LL*fac[i-1]*i%mod; 11 for(int i=2;i<N-4;i++)inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; 12 for(int i=1;i<N-4;i++)inv[i]=1LL*inv[i-1]*inv[i]%mod; 13 } 14 int c(int n,int m){ 15 return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod; 16 } 17 int calc(int m){ 18 if (pos[m].first==k)return 0; 19 int s=0; 20 for(int i=0;i<k;i++)sum[i]=1; 21 for(int i=m;i;i--){ 22 if ((a[m-i+1])&&(pos[i].second==k))return 0; 23 sum[pos[i].first]--; 24 sum[pos[i].second]-=a[m-i+1]; 25 } 26 for(int i=k-1;i>=0;i--){ 27 sum[i]+=sum[i+1]; 28 if (sum[i]<0)return 0; 29 } 30 s=fac[m]; 31 for(int i=1,j=1;i<=m;i=j){ 32 while ((j<=m)&&(a[i]==a[j]))j++; 33 s=1LL*s*inv[j-i]%mod; 34 } 35 int l1=0,l2=0; 36 for(int i=1;i<=m;i++)l1+=max(a[i],1); 37 l1=l1*2-1; 38 for(int i=1;i<=m;i++)l2+=a[i]+1; 39 l2=l2*2+1; 40 return 1LL*c(n+(l2-l1)-1,l2-1)*s%mod; 41 } 42 void dfs(int k,int las,int s){ 43 ans=(ans+calc(k-1))%mod; 44 for(int i=1;i<k;i++) 45 if (a[i]==1){ 46 a[i]=0; 47 ans=(ans+calc(k-1))%mod; 48 } 49 for(int i=1;i<k;i++) 50 if (!a[i])a[i]=1; 51 for(a[k]=las;a[k]<=s;a[k]++)dfs(k+1,a[k],s-a[k]); 52 } 53 int main(){ 54 init(); 55 scanf("%d%d%s",&n,&k,s); 56 for(int i=1,x=0,y=0;i<=n;i++){ 57 while ((x<k)&&(s[x]=='b'))x++; 58 y=max(x,y); 59 while ((y<k)&&(s[y]=='r'))y++; 60 pos[i]=make_pair(x,y); 61 if (x<k)x++; 62 if (y<k)y++; 63 } 64 dfs(1,1,(n+1)/2); 65 printf("%d",ans); 66 }