毒瘤题
发现操作序列的长度只和 B B B的数目有关,并且操作序列一定形如 r b ? ? ? . . . rb???... rb???...的形式,这个不太好证
考虑暴力 D P DP DP的本质
记 B B B的数目为 k i k_i ki,发现应该按 k i k_i ki从大到小加入,过程中 维护 b b b的匹配情况,这样转移是 O ( 1 ) O(1) O(1)的
发现这样处理不了最后一段的情况,交上去 w a wa wa了一半
发现可以枚举 k i = 0 k_i=0 ki=0的数目 x 1 x_1 x1以及 k i ≥ 1 k_i\ge 1 ki≥1的数目 x 2 x_2 x2,然后把前 x 1 + x 2 x_1+x_2 x1+x2个 a a a删掉,转移第 i i i段的时候就对第 i i i个 b b b和第 i + 1 i+1 i+1个 b b b中间的部分去匹配 ? ? ?就好了。有点抽象
这个做法常数非常小。所以肯定是可以通过的。
这个做法复杂度 O ( n 6 log n ) O(n^6\log n) O(n6logn)。
考虑这个做法的本质
发现只用枚举 x 1 + x 2 x_1+x_2 x1+x2就好了,这样优化到了 O ( n 5 log n ) O(n^5\log n) O(n5logn)。
应该有更加高妙的贪心,但是我太菜了完全想不出来。
#include
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int mod=1e9+7;
int n,K;
string str;
ll fpow(ll x,ll y=mod-2){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}return z;
}
ll fac[75],inv[75],invnum[75];
void init(int n){
fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
for(int i=1;i<=n;i++)invnum[i]=inv[i]*fac[i-1]%mod;
}
void add(ll &x,ll y){
x=(x+y)%mod;
}
int sum[75],sum2[75],rk[75],rk2[75],sum3[75],cnt;
unordered_map<int,ll>dp[75][75][75];
ll binom(int x,int y){
if(x<0||y<0||x<y)return 0;
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int calc(int x,int y){
return x*75+y;
}
ll dfs(int i,int j,int k,int l,int x){
if(j>n+1)return 0;int tmp=calc(l,x);
if(dp[i][j][k].find(tmp)!=dp[i][j][k].end())return dp[i][j][k][tmp];
if(k==cnt){
if(l>=0)return binom(n+1,j);
return 0;
}
if(i==0)return 0;
ll res=0;
//不选
add(res,dfs(i-1,j,k,l,0));
//选
int tot=sum3[rk2[k+2]]-sum3[rk2[k+1]];
add(res,dfs(i,j+2*i-1,k+1,min(0,l-i+tot),x+1)*invnum[x+1]);
add(res,dfs(i,j+2*i,k+1,min(0,l-i+tot),x+1)*invnum[x+1]*2);
add(res,dfs(i,j+2*i+1,k+1,min(0,l-i+tot),x+1)*invnum[x+1]);
return dp[i][j][k][tmp]=res;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>K>>str,init(n+1);
for(int i=1;i<=K;i++){
sum[i]=sum[i-1],sum2[i]=sum2[i-1];
if(str[i-1]=='r')sum[i]++,rk[sum[i]]=i;
else sum2[i]++;
}ll res=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=sum2[K]&&i+j<=min(n,sum[K]);j++){
int x=1;
for(int k=1;k<=K;k++){
if(str[k-1]=='b'&&x<=j&&k>rk[x])rk2[x++]=k;
sum3[k]=sum3[k-1];if(str[k-1]=='b'||sum[k]>i+j)sum3[k]++;
}if(x<=j)continue;rk2[x]=K+1;sum3[K+1]=sum3[K]+1;
for(int k=1;k<=n;k++){
for(int l=0;l<=n+1;l++){
for(int m=0;m<=j;m++){
dp[k][l][m].clear();
}
}
}
cnt=j,add(res,dfs(n,cnt+2*i,0,0,0)*fac[i+j]%mod*inv[i]%mod);
}
}cout<<res;
}