• 【BZOJ 4572】【SCOI 2016】围棋


    http://www.lydsy.com/JudgeOnline/problem.php?id=4572
    轮廓线DP:设(f(i,j,S,x,y))
    (S)表示((i,1))((i,j))((i-1,j+1))((i-1,m))的长度为m的轮廓线上与每个位置作为末位是否与第一个串匹配的状态。
    (x,y)分别表示((i,j))这个位置作为末位与第一/二个串kmp到了哪个位置。
    (x,y)取值范围是([0,c)),因为当(x,y)其一取到c时,这个状态主要考虑对下一个位置上状态的贡献,所以会沿着失配指针往前跳一个继续匹配,不如把(x/y=c)的状态和(x/y=fail[c])的状态压在一起。
    注意有的连通性状压轮廓线长度为m+1,这个不关心8联通,所以长度为m。
    又因为(S)的前(c-1)位一定是0,可以不记录这几位,所以S的长度是(m-c+1)
    时间复杂度(O(nm2^{m-c+1}c^2))
    注意滚动数组一定要全部清空!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    
    const int mo = 1000000007;
    
    int n, m, c, q, r1[10], r2[10], fail1[10], fail2[10];
    int f[1 << 12][6][6], g[1 << 12][6][6], t1[10][10], t2[10][10];
    char c1[10], c2[10];
    
    int change(int S, int tmp, int mark) {
    	if (tmp < 0) return S;
    	return S ^ ((mark ^ ((S >> tmp) & 1)) << tmp);
    }
    
    int ipow(int a, int b) {
    	int ret = 1, w = a;
    	while (b) {
    		if (b & 1) ret = 1ll * ret * w % mo;
    		w = 1ll * w * w % mo;
    		b >>= 1;
    	}
    	return ret;
    }
    
    int main() {
    	scanf("%d%d%d%d", &n, &m, &c, &q);
    	int ans_tot = ipow(3, n * m);
    	while (q--) {
    		scanf("%s%s", c1 + 1, c2 + 1);
    		for (int i = 1; i <= c; ++i) {if (c1[i] == 'W') r1[i] = 1; if (c1[i] == 'B') r1[i] = 2; if (c1[i] == 'X') r1[i] = 0;}
    		for (int i = 1; i <= c; ++i) {if (c2[i] == 'W') r2[i] = 1; if (c2[i] == 'B') r2[i] = 2; if (c2[i] == 'X') r2[i] = 0;}
    		
    		int p = 0;
    		for (int i = 2; i <= c; ++i) {
    			while (p && r1[p + 1] != r1[i]) p = fail1[p];
    			fail1[i] = r1[p + 1] == r1[i] ? ++p : 0;
    		}
    		p = 0;
    		for (int i = 2; i <= c; ++i) {
    			while (p && r2[p + 1] != r2[i]) p = fail2[p];
    			fail2[i] = r2[p + 1] == r2[i] ? ++p : 0;
    		}
    		
    		for (int i = 0; i < c; ++i)
    			for (int j = 0; j <= 2; ++j) {
    				p = i; while (p && r1[p + 1] != j) p = fail1[p];
    				t1[i][j] = r1[p + 1] == j ? p + 1 : 0;
    				p = i; while (p && r2[p + 1] != j) p = fail2[p];
    				t2[i][j] = r2[p + 1] == j ? p + 1 : 0;
    			}
    		
    		memset(f, 0, sizeof(f));
    		memset(g, 0, sizeof(g));
    		g[0][0][0] = 1;
    		int bas = (1 << (m - c + 1)) - 1, newx, newy, T;
    		for (int i = 1; i <= n; ++i) {
    			for (int j = 1; j <= m; ++j) {
    				if (j != 1) memcpy(f, g, sizeof(f));
    				else {
    					memset(f, 0, sizeof(f));
    					for (int S = 0; S <= bas; ++S)
    						for (int x = 0; x < c; ++x)
    							for (int y = 0; y < c; ++y)
    								if (g[S][x][y])
    									(f[S][0][0] += g[S][x][y]) %= mo;
    				}
    				memset(g, 0, sizeof(g));
    				
    				for (int S = 0; S <= bas; ++S)
    					for (int x = 0; x < c; ++x)
    						for (int y = 0; y < c; ++y)
    							if (f[S][x][y])
    								for (int now = 0; now <= 2; ++now) {
    									newx = t1[x][now]; newy = t2[y][now];
    									if (newy == c && j - c >= 0 && ((S >> (j - c)) & 1)) continue;
    									if (newx == c) T = change(S, j - c, 1);
    									else T = change(S, j - c, 0);
    									if (newx == c) newx = fail1[c];
    									if (newy == c) newy = fail2[c];
    									(g[T][newx][newy] += f[S][x][y]) %= mo;
    								}
    			}
    		}
    		
    		int ans = ans_tot;
    		for (int S = 0; S <= bas; ++S)
    			for (int x = 0; x < c; ++x)
    				for (int y = 0; y < c; ++y)
    					((ans -= g[S][x][y]) += mo) %= mo;
    		printf("%d
    ", ans);
    	}
    }
    
  • 相关阅读:
    第52周二Restful
    第52周一
    第51周日
    第51周六
    第51周五
    第51周四
    第51周三
    第51周二
    第51周一
    第50周日
  • 原文地址:https://www.cnblogs.com/abclzr/p/6599699.html
Copyright © 2020-2023  润新知