arc196c

思路

容斥。

钦定有 个分解线, 段中后面的不能连向前面的,每段中可能还有更小的段,系数为

规定一个段以白点结尾。可以合法的前缀中每个黑点都要被前缀中的白点匹配,即前缀中白点数要多于黑点。

把所有白点单独拉出来,设它们在原序列中下标为 ,在这个长为 的新序列上 dp。

表示钦定最后一段结尾为 的带系数的方案数。枚举前一个 中匹配了 对,剩 个白点,选出 个和 中的黑点匹配。

半在线卷积。,将 相同的 放一起,可以看作 卷积。即下标在 范围内的两个数组卷积,虽然单个长度没有办法保证,但是一整层的长度之和保证为

复杂度

code

int n;
char s[maxn<<1];
int p[maxn],f[maxn];
int fac[maxn],inv[maxn];
int C(int m,int n){return fac[m]*inv[n]%mod*inv[m-n]%mod;}
void sovle(int l,int r){
    if(l==r){
        if(l>=p[l]-l)f[l]=(C(l,p[l]-l)*fac[p[l]-l]+mod-f[l])%mod;
        else f[l]=0;
        return ;
    }
    int mid=l+r>>1;
    sovle(l,mid);
    int fl=p[l]-l,fr=p[mid]-mid,gl=max(0ll,mid+1-(p[mid]-mid)),gr=max(0ll,r-(p[l]-l));
    vector<int> ff(fr-fl+1),gg(gr-gl+1);
    for(int i=l;i<=mid;i++)if(i>=p[i]-i)(ff[p[i]-i-fl]+=f[i])%=mod;
    for(int i=gl;i<=gr;i++)gg[i-gl]=fac[i];
    vector<int> hh=mul(ff,gg);
    for(int i=mid+1;i<=r;i++)if(i>=p[i]-i)(f[i]+=hh[i-fl-gl]*inv[2*i-p[i]])%=mod;
    sovle(mid+1,r);
}
void work(){
    n=read();scanf("%s",s+1);
    if(s[1]=='W'||s[2*n]=='B'){puts("0");return ;}
    n=0;for(int i=1;s[i]=='W'||s[i]=='B';i++)if(s[i]=='W')p[++n]=i;
    fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    inv[n]=ksm(fac[n]);for(int i=n-1;~i;i--)inv[i]=inv[i+1]*(i+1)%mod;
    sovle(1,n);
    // for(int i=1;i<=n;i++){
    //     f[i]=C(i,p[i]-i)*fac[p[i]-i]%mod;
    //     for(int j=1;j<i;j++)(f[i]+=mod-C(i-(p[j]-j),p[i]-i-(p[j]-j))*fac[p[i]-i-(p[j]-j)]%mod*f[j]%mod)%=mod;
    //     // cout<<i<<" "<<p[i]<<" "<<f[i]<<"\n";
    // }
    // for(int i=1;i<=n;i++)cout<<i<<" "<<p[i]<<" "<<f[i]<<"\n";
    printf("%lld\n",f[n]);
}