【PA2019】Trzy Kule

组合计数,前缀和。

题目大意:

给定三个长度为 $n$ 的 01 串 $s_1,s_2,s_3$。

问有多少个长度为 $n$ 的 01 串 $s’$ 至少满足下列三个条件中的一个:

  • $\sum\limits_{i=1}^n |s_{1,i}-s’_i|\leq t_1$
  • $\sum\limits_{i=1}^n |s_{2,i}-s’_i|\leq t_2$
  • $\sum\limits_{i=1}^n |s_{3,i}-s’_i|\leq t_3$

题解:

我们可以先把 $s_1$ 变为全 $1$,$s_2$ 和 $s_3$ 进行变换使得每一位都对应即可。

总的字符串个数是 $2^n$,我们考虑求出以上三个条件都不满足的串的个数。

我们考虑每个位,由于 $s_1$ 已经是全 $1$,那么三个字符串的这个位的情况只有四种:100101110111。设它们的出现次数分别为 $a_1,a_2,a_3,a_4$。

我们考虑枚举 110111 的出现个数 $i,j$,那么 001000 的出现个数就为 $a_3-i$,$a_4-j$。

这种情况下,第一个字符串和第二个字符串中出现的 $1$ 的个数是一样的,都是 $i+j$,而第三个字符串中出现的 $1$ 的个数为 $i+a_4-j$。

我们设 100101 的出现次数分别为 $x,y$,那么我们需要满足以下三个不等式,才能对不满足条件的串产生贡献。

  • $i+j+x+y\gt t_1$
  • $i+j+(a_1-x)+(a_2-y)\gt t_2$
  • $i+(a_4-j)+(a_1-x)+y\gt t_3$

整理后可得:

  • $i+j\gt t_1-x-y$
  • $i+j\gt t_2-(a_1-x)-(a_2-y)$
  • $i+(a_4-j)\gt t_3-(a_1-x)-y$

可以合并为两个式子 $i+j\gt \max(t_1-x-y,t_2-(a_1-x)-(a_2-y))$,$i-j\gt t_3-(a_1-x)-y-a_4$。

$(i+j,i-j)$ 是可以唯一确定一组 $i,j$ 的。

不难发现,可以和一组 $x,y$ 产生贡献的 $i,j$,其对应的 $(i+j,i-j)$ 都落在一个矩形区域内。

那么,我们可以先枚举 $i,j$,其本身有 $\binom{a_3}i\binom{a_4}j$ 种不同方案。我们把这个方案加到二维平面上的点 $(i+j,i-j)$ 处。

然后枚举 $x,y$,其本身有 $\binom{a_1}x\binom{a_2}y$ 种不同方案。我们需要统计一个矩形区域内的和,这个可以预处理二维前缀和。之后用乘法原理即可计算方案数。

时空复杂度 $O(n^2)$。可能需要卡常。

Code:

#pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=10005,md=1e9+7;
int t1,t2,t3,_111,_101,_100,_110,n,fac[N],iv[N];
char s1[N],s2[N],s3[N];
inline int pow(int a,int b){
    int ret=1;
    for(;b;b>>=1,a=(LL)a*a%md)if(b&1)ret=(LL)ret*a%md;
    return ret;
}
inline int C(int x,int y){return(LL)fac[x]*iv[y]%md*iv[x-y]%md;}
int D[N][N],ans;
inline void upd(int&a){a+=a>>31&md;}
int main(){
    scanf("%d%d%s%d%s%d%s",&n,&t1,s1+1,&t2,s2+1,&t3,s3+1);
    for(int i=1;i<=n;++i){
        if(s1[i]==s2[i]&&s2[i]==s3[i])++_111;else
        if(s1[i]==s2[i])++_110;else
        if(s1[i]==s3[i])++_101;else
        ++_100;
    }
    if(_110>_101)swap(_110,_101),swap(t2,t3);
    if(_110>_100)swap(_110,_100),swap(t1,t3);
    for(int i=*fac=1;i<=n;++i)fac[i]=(LL)fac[i-1]*i%md;
    iv[n]=pow(fac[n],md-2);
    for(int i=n-1;~i;--i)iv[i]=(i+1LL)*iv[i+1]%md;
    for(int i=0;i<=_110;++i)
    for(int j=0;j<=_111;++j){
        int A=i+j,B=j+_110-i;
        D[A][B]=(D[A][B]+C(_110,i)*(LL)C(_111,j))%md;
    }
    for(int i=_110+_111;~i;--i){
        int*X=D[i],*Y=D[i+1];
        for(int j=_110+_111-max(i-_111,0);~j;--j)
        X[j]=((LL)X[j]+Y[j]+X[j+1]-Y[j+1]+md)%md;
    }
    for(int i=0;i<=_100;++i)
    for(int j=0;j<=_101;++j){
        int LA=max(t1+1-i-j,t2+1-(_100-i)-(_101-j)),LB=t3+1-(j+_100-i);
        if(LA<0)LA=0;if(LB<0)LB=0;
        ans=(ans+(LL)D[LA][LB]*C(_100,i)%md*C(_101,j))%md;
    }
    upd(ans=pow(2,n)-ans);
    printf("%d\n",ans);
    return 0;
}