【LOJ】#2017. 「SCOI2016」围棋

题解

考虑到状态数比较复杂,其实我们需要轮廓线dp……
我们设置\(f[x][y][S][h][k]\)为考虑到第(x,y)个格子,S是轮廓线上的匹配状态,是二进制,如果一位是1表示这一位匹配第一行匹配到第一行的末尾了,然后h是前一个格子匹配到第一行第h列,k是前一个格子匹配到第二行第k列,转移数组用kmp求出来,就是第几列,往下匹配一个字符能最远转移到哪
然后转移就可以了,如果下一次能匹配到末尾,那么S这一位就设成1,如果不能,S这一位就设成0
注意如果这个格子是一行的起始,需要特殊转移,强制是从匹配到第0列转移过来

代码

#include <bits/stdc++.h>
//#define ivorysi

typedef long long int64;
typedef unsigned int u32;
using namespace std;
int n,m,c,Q;
char A[15],B[15],ch[5];
int to[2][15][4],nx[15];
int f[2][1 << 12][7][7];
const int MOD = 1000000007;
void kmp(char *s,int id) {
    nx[1] = 0;
    for(int i = 2 ; i <= c; ++i) {
	int p = nx[i - 1];
	while(p && s[p + 1] != s[i]) p = nx[p];
	if(s[p + 1] == s[i]) nx[i] = p + 1;
	else nx[i] = 0;
    }
    for(int i = 0 ; i <= c ; ++i) {
	for(int j = 1 ; j <= 3 ; ++j) {
	    int p = i;
	    while(p && s[p + 1] != ch[j]) p = nx[p];
	    if(s[p + 1] == ch[j]) to[id][i][j] = p + 1;
	    else to[id][i][j] = 0;
	}
    }
}
void Init() {
    scanf("%s%s",A + 1,B + 1);
    kmp(A,0);kmp(B,1);
}
void update(int &x,int y) {
    x = (x + y) % MOD;
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
	if(c & 1) res = 1LL * res * t % MOD;
	t = 1LL * t * t % MOD;
	c >>= 1;
    }
    return res;
}
void Solve() {
    ch[1] = 'B';ch[2] = 'W';ch[3] = 'X';
    scanf("%d%d%d%d",&n,&m,&c,&Q);
    while(Q--) {
	Init();
	int cur = 0;
	memset(f[cur],0,sizeof(f[cur]));
	f[cur][0][0][0] = 1;
	int res = fpow(3,n * m);
	for(int i = 1 ; i <= n ; ++i) {
	    for(int j = 1 ; j <= m ; ++j) {
		memset(f[cur ^ 1],0,sizeof(f[cur ^ 1]));
		for(int S = 0 ; S < 1 << m ; ++S) {
		    for(int h = 0 ; h <= c ; ++h) {
			for(int k = 0 ; k <= c ; ++k) {
			    int x = f[cur][S][h][k];
			    if(!x) continue;
			    for(int l = 1 ; l <= 3 ; ++l) {
				int nx = to[0][h][l];
				if(j == 1) nx = to[0][0][l];
				int ny = to[1][k][l];
				if(j == 1) ny = to[1][0][l];
				int nS = S;
				if((S>> j - 1 & 1) && ny == c) continue;
				if(nx == c) {
				    if(!(nS >> j - 1 & 1)) nS ^= 1 << j - 1;
				}
				else {
				    if(nS >> j - 1 & 1) nS ^= 1 << j - 1;
				}
				if(i == n && j == m) update(res,MOD - x);
				else update(f[cur ^ 1][nS][nx][ny],x);
			    }
			}
		    }
		}
		cur ^= 1;
	    }
	}
	printf("%d\n",res);
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}
posted @ 2018-06-08 15:22  sigongzi  阅读(170)  评论(0编辑  收藏  举报