【BZOJ1055】[HAOI2008]玩具取名【区间DP】【状压】

【题目链接】

一开始WA,以为DP写跪了,最后发现是hash数组开小了...


设dp[x][y]表示[x, y]这个区间可以化简成的最简状态,其中状态用0到15的二进制表示。

转移时候分割区间,得到两个区间的状态,然后看有没有对应的字符即可。

边界状态是区间长度为1,和区间长度为2两种。


/* Footprints In The Blood Soaked Snow */
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 205;

int n, W, I, N, G, hash[750], dp[maxn][maxn];
char str[maxn];

inline int gethash(char a, char b) {
	return (a - 'A') * 26 + (b - 'A');
}

inline char zip(int a) {
	if(a == 0) return 'W';
	if(a == 1) return 'I';
	if(a == 2) return 'N';
	if(a == 3) return 'G';
}

inline int getans(int s1, int s2) {
	int ans = 0;
	for(int i = 0; i < 4; i++) for(int j = 0; j < 4; j++) {
		int a = s1 & (1 << i), b = s2 & (1 << j);
		if(!a || !b) continue;
		ans |= hash[gethash(zip(i), zip(j))];
	}
	return ans;
}

inline int dfs(int x, int y) {
	if(x == y) {
		if(str[x] == 'W') return dp[x][y] = 1;
		if(str[x] == 'I') return dp[x][y] = 2;
		if(str[x] == 'N') return dp[x][y] = 4;
		if(str[x] == 'G') return dp[x][y] = 8;
	}
	if(y - x + 1 == 2) return dp[x][y] = hash[gethash(str[x], str[y])];
	if(dp[x][y]) return dp[x][y];

	int ans = 0;
	for(int i = x; i < y; i++) {
		int l = dfs(x, i), r = dfs(i + 1, y);
		if(!l || !r) continue;
		ans |= getans(l, r);
	}
	return dp[x][y] = ans;
}

int main() {
	scanf("%d%d%d%d", &W, &I, &N, &G);
	for(int i = 1; i <= W; i++) {
		scanf("%s", str);
		hash[gethash(str[0], str[1])] |= 1;
	}
	for(int i = 1; i <= I; i++) {
		scanf("%s", str);
		hash[gethash(str[0], str[1])] |= 2;
	}
	for(int i = 1; i <= N; i++) {
		scanf("%s", str);
		hash[gethash(str[0], str[1])] |= 4;
	}
	for(int i = 1; i <= G; i++) {
		scanf("%s", str);
		hash[gethash(str[0], str[1])] |= 8;
	}
	scanf("%s", str); n = strlen(str);

	int ans = dfs(0, n - 1);
	if(!ans) {
		printf("The name is wrong!\n");
		return 0;
	}
	if(ans & 1) printf("W");
	if(ans & 2) printf("I");
	if(ans & 4) printf("N");
	if(ans & 8) printf("G");
	printf("\n");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值