bzoj4572: [Scoi2016]围棋

8 篇文章 0 订阅
1 篇文章 0 订阅

这道题我只会子集和变换优化的sb暴力(什么轮廓线插头都忘光了…)
考虑到合法状态的稀疏性(其实是你自己不会证明吧……),就可以放心暴力啦;

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
using namespace std;
const int mod=1e9+7;
const int N=5e4+7;
const int M=5e5+7;
void upd(int& x,int y){
    x+=y;if(x>=mod)x-=mod;
}
int qpow(int a,int b){
    int res=1,aa=a;
    for(;b;b>>=1){if(b&1)res=1ll*res*aa%mod;aa=1ll*aa*aa%mod;}
    return res;
}
int n,m,c,T,mo[2][17],b[17],stk[N],top;
vector<int> tu[N];
char s[2][17];
struct E{
    int to,w,next;E(int to=0,int w=0,int next=0):to(to),w(w),next(next){}
}edge[M];
int head[N],tot;
void add(int x,int y,int w){
    edge[++tot]=E(y,w,head[x]);head[x]=tot;
}
int f[2][N],now;

int trans(int x,int op){
    rep(i,0,m-1)b[i]=x%3,x/=3;
    int res=0;
    rep(i,0,m-c){int j;
        for(j=0;j<c && mo[op][j]==b[i+j];j++);
        if(j==c)res|=(1<<(i+c-1));
    }return res;
}
void init(){
    int S=qpow(3,m)-1;
    rep(i,0,S){
        int k1=trans(i,0);
        int k2=trans(i,1);
        tu[k1].push_back(k2);
    }S=(1<<m)-1;
    top=0;
    rep(i,0,S){
        int lim=tu[i].size();
        if(lim){
            f[0][i]=lim;
            sort(tu[i].begin(),tu[i].end());

            stk[++top]=i;
            int last=tu[i][0],cc=1;
            rep(j,1,lim-1){
                if(tu[i][j]==last)cc++;
                else{
                    add(i,last,cc);
                    last=tu[i][j],cc=1;
                }
            }
            add(i,last,cc);
        }
    }
}
void change(int op){
    int S=(1<<m)-1;
    rep(i,0,m-1){
        rep(j,0,S){
            if(j&(1<<i))upd(f[op][j],f[op][j^(1<<i)]);
        }
    }
}
void dp(){
    now=0;
    int S=(1<<m)-1;
    rep(i,1,n-1){
        now^=1;
        memset(f[now],0,sizeof(f[now]));
        change(now^1);
        rep(j,1,top){
            int u=stk[j];
            for(int kk=head[u];kk;kk=edge[kk].next){
                int v=edge[kk].to;
                int w=edge[kk].w;
                upd(f[now][u],1ll*w*f[now^1][S^v]%mod);
            }
        }
    }change(now);
    int ans=qpow(3,n*m);
    upd(ans,mod-f[now][S]);
    printf("%d\n",ans);
}
int main(){
    scanf("%d%d%d%d",&n,&m,&c,&T);
    while(T--){
        rep(i,0,(1<<m)-1)tu[i].clear();
        memset(head,0,sizeof(head));
        memset(f,0,sizeof(f));
        tot=0;
        scanf("%s%s",s[0],s[1]);
        rep(i,0,c-1)if(s[0][i]=='B')mo[0][i]=1;else if(s[0][i]=='W')mo[0][i]=2;else mo[0][i]=0;
        rep(i,0,c-1)if(s[1][i]=='B')mo[1][i]=1;else if(s[1][i]=='W')mo[1][i]=2;else mo[1][i]=0;
        init();
        dp();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值