• bzoj4572: [Scoi2016]围棋


    传送门

    n==2的点随便怎么dp一下就好了。

    然后考虑正经的做法,无脑暴力枚举上下两行的状态的话是n*m*3^m*3^m

    容易想到把上一行用二进制表示以第i个数结尾能不能完全匹配第一行的串,这样大概有n*m*2^m*3^m

    好像有60了吧。

    如果可以只保存上一行的状态和这一行的匹配情况岂不是美滋滋,但是这样我无法向下一行转移啊。

    于是就咕咕咕了。

    考虑上一行的二进制串,这一行匹配到第j位时前j位都没有用了,那我岂不是可以直接把这一行的压上去!

    没错就是轮廓线dp啊。

    于是就做完了。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<ctime>
    #include<cmath>
    const int mod=1e9+7;
    typedef long long LL;
    using namespace std;
    int n,m,c,q,nn; 
    int dp[101][13][(1<<10)+1][7][7],nx1[10],nx2[10];
    char s1[10],s2[10],ss[10]={'W','B','X'};
    
    template<typename T> void read(T &x) {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    void make_nxt(char s[],int nxt[]) {
        for(int i=1,k=0;i<c;i++) {
            while(k&&s[k]!=s[i]) k=nxt[k-1];
            if(s[k]==s[i]) k++;
            nxt[i]=k;
        }
    }
    
    void clear() {
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        for(int k=0;k<=nn;k++)
        for(int x=0;x<=c;x++)
        for(int y=0;y<=c;y++) 
        dp[i][j][k][x][y]=0; 
    }
    
    void add(int &x,int y) { LL res=x; res+=y; if(res>=mod) res-=mod; x=res; }
    
    int main() {
        read(n); read(m); read(c); read(q);
        LL power=1;
        for(int i=1;i<=n*m;i++) (power*=3)%=mod;
        while(q--) {
            scanf("%s%s",s1,s2);
            make_nxt(s1,nx1); make_nxt(s2,nx2);
            nn=(1<<(m-c+1))-1;
            dp[0][m][0][0][0]=1;
            LL ans=0;
            for(int i=0;i<=n;i++) {
                for(int j=(i==0?m:1);j<=m;j++) {
                    for(int s=0;s<=nn;s++) {
                        for(int x=0;x<=c;x++)
                        for(int y=0;y<=c;y++) if(dp[i][j][s][x][y]) {
                            if(i==n&&j==m) (ans+=dp[i][j][s][x][y])%=mod;
                            int ni,nj,nx,ny,ns;
                            for(int k=0;k<3;k++) {
                                if(j==m) ni=i+1,nj=1,nx=0,ny=0;
                                else ni=i,nj=j+1,nx=x,ny=y; ns=s;
                                while(nx&&ss[k]!=s1[nx]) nx=nx1[nx-1];
                                if(ss[k]==s1[nx]) nx++;
                                while(ny&&ss[k]!=s2[ny]) ny=nx2[ny-1];
                                if(ss[k]==s2[ny]) ny++;
                                if(ny==c&&(s&(1<<nj-c))) continue;
                                if(nx==c&&(!(ns&(1<<nj-c)))) ns|=(1<<nj-c);
                                else if(nx!=c&&(ns&(1<<nj-c))) ns^=(1<<nj-c);
                                if(ni>n||nj>m) continue;
                                add(dp[ni][nj][ns][nx][ny],dp[i][j][s][x][y]);
                            }
                        }
                    }
                }
            }
            ans=(power-ans+mod)%mod;
            printf("%lld
    ",ans);
            if(q) clear();
        }
        return 0;
    }
    /*
    3 3 2 3
    XB
    BW
    BX
    XB
    BB
    BB
    */
    View Code
  • 相关阅读:
    leetcode 203. Remove Linked List Elements 删除链表中的某个值 ---------- java
    leetcode 202. Happy Number 判断一个数是否是“Happy Number” ---------- java
    leetcode 201. Bitwise AND of Numbers Range 求范围中,每一位都是1的数 ---------- java
    js获取Html元素的实际宽度高度
    jquery中this与$this的区别
    find()与children()方法的区别
    jquery创建动态的div
    兼容性问题
    bootstrap插件小记
    禁掉a链接的几种方法
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8399968.html
Copyright © 2020-2023  润新知