Codeforces 1105F Helping Hiasat

Codeforces 1105F Helping Hiasat

题目链接

http://codeforces.com/contest/1105/problem/E

题目大意

有 $m$ 个人和 $n$ 个操作,操作一为可以修改用户名,操作二为某个人去查看用户名。如果一个人每次查用户名的时候用户名都是他想看的那个,那么他就是开心的,问最多有多少个人可以开心。

题目分析

由题目可知,在两个 $1$ 操作之间的所有人都会冲突,所以可以先预处理所有冲突的人。则任何一个人都不能和与他冲突的人同时被选择。很明显的做法是状压 $DP$ 。但是 $m$ 的上界是 $40$ 不好满足状压 $DP$ 的时限要求。考虑可以将所有人分成两组,组内先进行状压 $DP$ ,随后可以将两组合并,即可得到答案。注意到每个人的冲突关系可以先预处理出来二进制表示,可以将复杂度减少一维。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

int n, m, t;

vector <int> vec;

bool a[55][55];

map <string, int> s;
int sc = 0;

int f[(1 << 21)];
int g[(1 << 21)];

int va[55];
int vb[55];

int read(){
	int x;
	scanf("%d", &x);
	return x;
}

int getn(string str){
	if(!s[str]){
		s[str] = ++sc;
	}
	
	return s[str];
}

int getp(int x, int p){
	return (x >> (p - 1)) & 1;
}

int addp(int x, int p){
	return x | (1 << (p - 1));
}

int main(){
	ios::sync_with_stdio(0); cin.tie(0);
	int i, j, k;
	int op;
	string str;
	int hf;
	int ans = 0;
	
	cin >> n >> m;
	
	hf = m / 2 + 1;
	
	for(i=1;i<=n;i++){
		cin >> op;
		if(op == 1){
			for(k=0;k<vec.size();k++){
				for(j=k+1;j<vec.size();j++){
					a[vec[k]][vec[j]] = true;
					a[vec[j]][vec[k]] = true;
				}
			}
			vec.clear();
		}else{
			cin >> str;
			vec.push_back(getn(str));
		}
	}
	
	for(k=0;k<vec.size();k++){
		for(j=k+1;j<vec.size();j++){
			a[vec[k]][vec[j]] = true;
			a[vec[j]][vec[k]] = true;
		}
	}
	
	for(i=1;i<=hf;i++){
		for(j=1;j<=hf;j++){
			if(a[i][j]){
				va[i] = addp(va[i], j);
			}
		}
	}
	
	for(i=1;i<=(m-hf);i++){
		for(j=1;j<=(m-hf);j++){
			if(a[i + hf][j + hf]){
				va[i + hf] = addp(va[i + hf], j);
			}
		}
	}
	
	for(i=1;i<=hf;i++){
		for(j=1;j<=(m-hf);j++){
			if(a[i][j + hf]){
				vb[j + hf] = addp(vb[j + hf], i);
			}
		}
	}
	
	for(i=0;i<(1<<hf);i++){
		for(j=1;j<=hf;j++){
			if(!getp(i, j)){
				bool flag = i & va[j];
				
				if(flag){
					f[addp(i, j)] = max(f[addp(i, j)], f[i]);
				}else{
					f[addp(i, j)] = max(f[addp(i, j)], f[i] + 1);
				}
			}
		}
		ans = max(ans, f[i]);
	}
	
	for(i=0;i<(1<<(m-hf));i++){
		for(j=1;j<=(m-hf);j++){
			if(!getp(i, j)){
				bool flag = i & va[hf + j];
				
				if(flag){
					g[addp(i, j)] = max(g[addp(i, j)], g[i]);
				}else{
					g[addp(i, j)] = max(g[addp(i, j)], g[i] + 1);
				}
			}
		}
		ans = max(ans, g[i]);
	}
	
	for(i=0;i<(1<<hf);i++){
		int tmp = 0;
		for(j=1;j<=(m-hf);j++){
			bool flag = i & vb[j + hf];
			
			if(!flag){
				tmp = addp(tmp, j);
			}
		}
		
		ans = max(ans, f[i] + g[tmp]);
	}
	
	cout << ans << endl;
	
	return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据