EZOJ#584. 【2020联赛训练1】染色

原题链接:染色

输入样例:

4
cabaacba

输出样例:

4

针对样例有\(4\)种染色方案如下

算法:折半搜索

可以发现如果左半边的颜色确定了,那么右半边的串的蓝红总数就确定了.
然后在右半边暴力搜索方案即可.
可以利用\(Hash\)快速统计串.

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;

typedef unsigned long long ULL;
typedef long long LL;

const int N = 110, P = 131;  //哈希时P一般取131

int n;
int col[N];
char s[N];
ULL h[N];
LL ans;
map<ULL, int> f[N / 2];

void check(int tag) {
	ULL x = 0, y = 0;
	int cnt = 0, cnt1 = n;
	for (int i = 1; i <= n; i++) {
		if (col[i] > 0) {
			x += (ULL)col[i] * h[cnt];
			cnt++;
		}
		else {
			y += (ULL)col[i] * h[cnt1];
			cnt1--;
		}
	}
	if (tag == 1)
		ans += f[cnt][x + y];
	else  
		f[cnt1][x + y]++;
}


void dfs1(int x) {
	if (x > n) {
		check(0);  //左边方案确定后,累加一下方案
		return;
	}
        //col[i](1<=i<=n)表示1~n的染色方案,若col[i]>0,表示这个字符染成红色,若col[i]<0,表示这个字符染成蓝色
	col[x] = s[x] - 'a' + 1;
	dfs1(x + 1);
	col[x] = -col[x];
	dfs1(x + 1);
}

void dfs2(int x) {
	if (x <= n) {
		check(1);
		return;
	}
        //col[i](1<=i<=n)分别表示2n~n+1的染色方案,若col[i]>0,表示这个字符染成蓝色,若col[i]<0,表示这个字符染成红色
	int tmp = 2 * n - x + 1;
	col[tmp] = s[x] - 'a' + 1;
	dfs2(x - 1);
	col[tmp] = -col[tmp];
	dfs2(x - 1); 
}

int main() {
	cin >> n;
	cin >> s + 1;
	h[0] = 1;
	for (int i = 1; i <= n; i++)  //预处理Hash每个位上的相应权值
		h[i] = h[i - 1] * P;
	dfs1(1);
	dfs2(2 * n);
	cout << ans << endl;
	return 0;
}
posted @ 2020-09-19 15:42  lew2018  阅读(99)  评论(0)    收藏  举报
Live2D