bzoj 3120 Line 矩乘 dp

来源:互联网 发布:node网站怎么绑定域名 编辑:程序博客网 时间:2024/06/05 23:54

每行结尾连续的1的个数只能是0,1,2。
状态记录一下有几行结尾连续的1的个数为0,几行结尾连续的1的个数为1,当前有多少列为全1。
然后矩乘转移就好了。

#include <bits/stdc++.h>using namespace std;#define ll long long#define mod 1000000007int n,P,Q,cnt,ans;ll m;struct Matrix{    int w[185][185];    void init()    {        memset(w,0,sizeof(w));        for(int i=1;i<=cnt;i++)w[i][i]=1;    }}mat,tmp;void mul(Matrix &a,Matrix &b,Matrix &c){    memset(&tmp,0,sizeof(tmp));    for(int i=1;i<=cnt;i++)        for(int k=1;k<=cnt;k++)if(a.w[i][k])            for(int j=1;j<=cnt;j++)if(b.w[k][j])                tmp.w[i][j]=(tmp.w[i][j]+(ll)a.w[i][k]*b.w[k][j])%mod;    c=tmp;}int num[5][11][11],C[11][11];Matrix qpow(Matrix x,ll y){    Matrix ret;ret.init();    while(y)    {        if(y&1)mul(ret,x,ret);        mul(x,x,x);y>>=1;    }    return ret;}int main(){    scanf("%d%lld%d%d",&n,&m,&P,&Q);    if(P==1)return puts("1"),0;    for(int i=0;i<=n;i++)C[i][0]=1;    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            C[i][j]=C[i-1][j-1]+C[i-1][j];    for(int i=0;i<=Q;i++)        for(int j=0;j<=n;j++)            for(int k=0;j+k<=n;k++)                if(P!=2||j+k==n)                    num[i][j][k]=++cnt;    for(int i=0;i<=Q;i++)        for(int a1=0;a1<=n;a1++)            for(int b1=0;b1+a1<=n;b1++)                if(P!=2||a1+b1==n)                {                    int t1=num[i][a1][b1];                    for(int a2=0;a2<=a1;a2++)                        for(int b2=0;b2<=b1;b2++)                            if(P!=2||b2==0)                            {                                int t2=num[i+(a2+b2==n)][(n-a1-b1)+(a1-a2)+(b1-b2)][a2];                                if(i+(a2+b2==n)>Q)continue;                                (mat.w[t1][t2]+=C[a1][a2]*C[b1][b2])%=mod;                            }                }    mat=qpow(mat,m);    int t=num[0][n][0];    for(int i=1;i<=cnt;i++)        ans=(ans+mat.w[t][i])%mod;    printf("%d\n",ans);    return 0;}
0 0