SCOI2016围棋

来源:互联网 发布:怎样做好淘宝才有生意 编辑:程序博客网 时间:2024/04/29 00:00

题目大意

有个n*m的格子图,每个格子上有三种数。
给出q个2*c模版,对于每个模版,求有多少种格子图能够匹配这个模版。

数据范围

这里写图片描述
q5

直观想法

fi,s表示现在匹配到第i行,第i行的状态为s(s为三进制数)的方案数。
转移显然。
然后这样的时间复杂度是O(n×32m)超时,估计只有20分。

缩减状态

每次计算匹配一个的。
可以发现,由于我们只要匹配一个模版,所以有许多的状态都是无用的,于是我们可以缩减状态。
如何缩减?
对于一个状态,我们关心的只是那个位置匹配了s0(或s1,注:s0表示模板的第一行,s1表示模版的第二行,以下都这样简称),那么对于每个确定的串,它是有两个二进制状态的,一个二进制位为1当且仅当以当前位为结尾的c为是与模版是一样的,举个例子:
这里写图片描述
然后由于前c-1位都不可能为1(因为一个二进制位为1当且仅当以当前位为结尾的c为是与模版是一样的),所以共有2mc+1种状态。
那么转移的东西如图(箭头表示由哪个数组推出哪个数组,可能本人比较蠢,用的数组太多了):
这里写图片描述
转移就很显然了,额如果不明白,看标称吧^_^
这样的时间复杂度就是O(n×22m2c+2)
空间复杂度为O(m×c2×22m2c+2)
然后,如果m-c比较大,它就会GG了
很遗憾,数据中真的有这样的数据。。。。。
这里写图片描述
庆幸的是,数据中的这个的n是等于2的,n=2又可以怎样做呢,于是他就可以直接dp就好了,设u[i][w0][w1]表示当前做到第i位,匹配到s0的w0,s1的w1,然后转移显然。。。。。
感觉很水的方法啊啊啊啊啊
说一句:有种水法的感觉
贴个代码哈哈哈哈哈哈:

#include<cstring>#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;typedef double db;int get(){    char ch;    int s=0;    bool pd=0;    while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');    if (ch=='-')pd=1;    else s=ch-'0';    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';    if (pd)return -s;    return s;}const int N = 110;const int M = 20;const int mo = 1e+9+7;const int zt = 260;int mi[13],n,m,c,q,len;int t[M][7][7][zt][zt],g[zt][zt],p[zt],v[zt][zt],w[zt],f[N][zt];int u[N][7][7];LL ans;int s[2][M];int next[2][M];LL v3[N*M];int trans(char ch){    switch (ch){    case 'W':return 0;    case 'B':return 1;    case 'X':return 2;    }}void init(int v){    char ch;    while(ch=getchar(),ch!='B'&&ch!='W'&&ch!='X');    s[v][1]=trans(ch);    fo(i,2,c)s[v][i]=trans(getchar());    int j=0;    fo(i,2,c){        while(j&&s[v][j+1]!=s[v][i])j=next[v][j];        if (s[v][j+1]==s[v][i])j++;        next[v][i]=j;    }}void work0(){    fo(ttt,1,q){        init(0);        init(1);        fo(i,0,m)fo(w0,0,c)fo(w1,0,c)u[i][w0][w1]=0;        u[0][0][0]=1;        ans=0;        fo(i,0,m-1)            fo(w0,0,c-1)                fo(w1,0,c-1)                if (u[i][w0][w1]){                    fo(v0,0,2)                        fo(v1,0,2){                            int _w0=w0,_w1=w1;                            while(_w0&&s[0][_w0+1]!=v0)_w0=next[0][_w0];                            if (s[0][_w0+1]==v0)_w0++;                            while(_w1&&s[1][_w1+1]!=v1)_w1=next[1][_w1];                            if (s[1][_w1+1]==v1)_w1++;                            if (_w0==c&&_w1==c)                                ans=(ans+LL(u[i][w0][w1])*v3[2*(m-1-i)]%mo)%mo;                            else{                                if (_w0==c)_w0=next[0][c];                                if (_w1==c)_w1=next[1][c];                                u[i+1][_w0][_w1]=(u[i+1][_w0][_w1]+u[i][w0][w1])%mo;                            }                        }                }        printf("%lld\n",ans);    }}void work1(){    fo(ttt,1,q){        init(0);        init(1);        fo(i,0,m)fo(w0,0,c)fo(w1,0,c)fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1)        t[i][w0][w1][t0][t1]=0;        fo(t0,0,mi[len]-1)fo(t1,0,mi[len]-1)g[t0][t1]=v[t0][t1]=0;        fo(t0,0,mi[len]-1)p[t0]=w[t0]=0;        fo(i,0,n)fo(t0,0,mi[len]-1)f[i][t0]=0;        t[0][0][0][0][0]=1;        fo(i,0,m-1)            fo(w0,0,c-1)                fo(w1,0,c-1)                    fo(t0,0,mi[len]-1)                        fo(t1,0,mi[len]-1)                        if (t[i][w0][w1][t0][t1]){                            fo(v,0,2){                                int _w0=w0,_w1=w1,_t0=t0,_t1=t1;                                while(_w0&&s[0][_w0+1]!=v)_w0=next[0][_w0];                                if (s[0][_w0+1]==v)_w0++;                                while(_w1&&s[1][_w1+1]!=v)_w1=next[1][_w1];                                if (s[1][_w1+1]==v)_w1++;                                if (_w0==c){                                    _w0=next[0][c];                                    _t0|=mi[i+1-c];                                }                                if (_w1==c){                                    _w1=next[1][c];                                    _t1|=mi[i+1-c];                                }                                t[i+1][_w0][_w1][_t0][_t1]=(t[i+1][_w0][_w1][_t0][_t1]+t[i][w0][w1][t0][t1])%mo;                            }                        }        fo(w0,0,c-1)            fo(w1,0,c-1)                fo(t0,0,mi[len]-1)                    fo(t1,0,mi[len]-1){                        g[t0][t1]=(g[t0][t1]+t[m][w0][w1][t0][t1])%mo;                        p[t1]=(p[t1]+t[m][w0][w1][t0][t1])%mo;                    }        fo(t0,0,mi[len]-1)            fo(t1,0,mi[len]-1)            if ((t1&t0)>0)w[t0]=(w[t0]+p[t1])%mo;            else                fo(_t0,0,mi[len]-1)                v[t0][_t0]=(v[t0][_t0]+g[t1][_t0])%mo;        f[0][0]=1;        ans=0;        fo(i,0,n-1)            fo(t0,0,mi[len]-1)            if (f[i][t0]){                ans=(ans+LL(f[i][t0])*w[t0]%mo*v3[(n-i-1)*m]%mo)%mo;                fo(_t0,0,mi[len]-1)                    f[i+1][_t0]=(f[i+1][_t0]+LL(f[i][t0])*v[t0][_t0]%mo)%mo;            }        printf("%lld\n",ans);    }}int main(){    n=get();m=get();c=get();q=get();    v3[0]=1;    fo(i,1,n*m)v3[i]=v3[i-1]*3%mo;    mi[0]=1;    fo(i,1,12)mi[i]=mi[i-1]*2;    len=m-c+1;    if (n==2)work0();    else work1();    return 0;}
0 0
原创粉丝点击