题目链接:https://codeforces.com/contest/1105/problem/E
题意:有 n 个事件,op = 1 表示我可以修改昵称,op = 2 表示一个名为 s_i 的朋友查询我当前的名字。一个朋友是高兴的当且仅当他每次查询我的名字都为 s_i,保证每个朋友至少查询一次我的名字,问最多可以有多少个朋友高兴。
题解:在我两次修改昵称之间,若出现不同的朋友,则他们是互斥的,可以在他们之间连一条边,然后求图的最大独立集,而原图的最大独立集等于补图的最大团,所以求补图的最大团即可。(模板)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset((a),(b),sizeof(a))
#define mp(a,b) make_pair(a,b)
#define pi acos(-1)
#define pii pair<int,int>
#define pb push_back
#define lowbit(x) ((x)&(-x))
const int INF = 0x3f3f3f3f;
const double eps = 1e-;
const int maxn = 1e5 + ;
const int maxm = 1e6 + ;
const ll mod = 1e9 + ; int n, m, tot = ;
map<string, int>ma, have;
int op[maxn];
string s[maxn]; int mx[], g[][], f[][], ans; int dfs(int cur, int tot) {
if(!cur) {
if(tot > ans)
return ans = tot, ;
return ;
}
for(int i = , j, u, nxt; i < cur; i++) {
if(cur - i + tot <= ans)
return ;
u = f[tot][i], nxt = ;
if(mx[u] + tot <= ans)
return ;
for(j = i + ; j < cur; j++)
if(g[u][f[tot][j]])
f[tot + ][nxt++] = f[tot][j];
if(dfs(nxt, tot + ))
return ;
}
return ;
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
scanf("%d%d", &m, &n);
for(int i = ; i <= m; i++) {
scanf("%d", &op[i]);
if(op[i] == ) {
cin >> s[i];
if(ma.find(s[i]) == ma.end())
ma[s[i]] = tot++;
}
}
vector<int>vec;
for(int i = ; i <= m; i++) {
if(op[i] == ) {
have.clear();
for(int i = ; i < vec.size(); i++) {
for(int j = i + ; j < vec.size(); j++) {
g[vec[i]][vec[j]] = g[vec[j]][vec[i]] = ;
}
}
vec.clear();
} else if(have.find(s[i]) == have.end())
vec.pb(ma[s[i]]);
}
for(int i = ; i < vec.size(); i++) {
for(int j = i + ; j < vec.size(); j++) {
g[vec[i]][vec[j]] = g[vec[j]][vec[i]] = ;
}
}
for(int i = ; i < n; i++)
for(int j = ; j < n; j++)
g[i][j] ^= ; int j,k;
for(int i = n - ; ~i; dfs(k, ), mx[i--] = ans)
for(k = , j = i + ; j < n; j++)
if(g[i][j])
f[][k++] = j;
printf("%d\n", ans);
return ;
}