题目链接:https://codeforces.com/contest/1230
A - Dawid and Bags of Candies
随便弄一下。
B - Ania and Minimizing
随便弄一下。
C - Anadi and Domino
看到这个题目意识到我好像做过这套题。
那么好像我是看过题解的,但是我没有补。
题意:给21种多米诺骨牌,以及不超过7个点的一个简单图,把多米诺骨牌放在边上,使得图的点对应多米诺骨牌的颜色。求最多能放多少个骨牌?
题解:多米诺骨牌的6种颜色是完全等价的,所以n<=6的时候每个点就染一种颜色即可。否则枚举7号点的颜色,然后贪心放就可以。
int edge[8][8];
int used[8][8];
void TestCase() {
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j)
edge[i][j] = 0;
}
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
edge[u][v] = 1;
edge[v][u] = 1;
}
if(n <= 6) {
printf("%d\n", m);
return;
}
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j)
used[i][j] = 0;
}
int cnt = 0;
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j) {
if(edge[i][j] && used[i][j] == 0) {
used[i][j] = 1;
used[j][i] = 1;
++cnt;
}
}
}
int ans = cnt;
for(int k = 1; k <= 6; ++k) {
int tmp = 0;
for(int i = 1; i <= 6; ++i) {
if(edge[7][i] && used[k][i] == 0)
++tmp;
}
ans = max(ans, cnt + tmp);
}
printf("%d\n", ans);
return;
}
上面这个代码WA10,想了想,不能强行要求7号点和前面的点同色,也可能同色的点在前面。所以应该两维枚举同色的点,然后给其他点染色再贪心分配。
int color[8];
int edge[8][8];
int used[8][8];
int ans;
void solve() {
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j)
used[i][j] = 0;
}
int cnt = 0;
for(int i = 1; i <= 7; ++i) {
for(int j = 1; j <= 7; ++j) {
if(edge[i][j] && used[color[i]][color[j]] == 0) {
++cnt;
used[color[i]][color[j]] = 1;
used[color[j]][color[i]] = 1;
}
}
}
ans = max(ans, cnt);
return;
}
void TestCase() {
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j)
edge[i][j] = 0;
}
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
edge[u][v] = 1;
edge[v][u] = 1;
}
if(n <= 6) {
printf("%d\n", m);
return;
}
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= 6; ++j)
used[i][j] = 0;
}
ans = 0;
for(int i = 1; i <= 7; ++i) {
for(int j = 1; j <= 7; ++j) {
if(j == i)
continue;
int top = 1;
color[i] = 1;
color[j] = 1;
for(int k = 1; k <= 7; ++k) {
if(k == i || k == j)
continue;
color[k] = ++top;
solve();
}
}
}
printf("%d\n", ans);
return;
}
D - Marcin and Training Camp
题意:有n个学生,第i个学生会60种算法中的某些(用ai的二进制位表示),而且有bi的技能值。一个学生x会觉得自己比学生y牛逼,当且仅当他知道一种学生y不知道的算法。注意两个学生可以互相觉得自己比对方牛逼。一个团队是冷静的,当且仅当没有人觉得自己比其他人都牛逼。选出一个至少两人的冷静的团队,使其技能值的和最大。
题解:可以看出,一个人只会觉那种懂得所有他会的算法的大佬比他牛逼或者与他完全相同。也就是一个人要变得冷静,必须要让另一个完全覆盖他的大佬来覆盖他,那么很明显可以观察出,最厉害的那个大佬必定是有一个和他水平一样的队友的,剩下的人都在这两个大佬会的算法的子集中选。
看见这个数据量可以过O(n^2)的算法。那么有一种暴力的算法:枚举每个人成为大佬,然后把比他牛逼的人全部去掉,看看是否有另一个相同的大佬队友,若有,则把剩下的人都加起来。
这个算法是错的,错在若干个冷静的团队是可以合并的。
所以先把所有有另一个完全相同的人的人选了,再选出他们各自技能子集中的人的并集,注意不能先取技能的并集再取子集。
pll p[7005];
bool vis[7005];
void TestCase() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lld", &p[i].first);
for(int i = 1; i <= n; ++i)
scanf("%lld", &p[i].second);
sort(p + 1, p + 1 + n);
for(int i = 2; i <= n; ++i) {
if(p[i].first == p[i - 1].first) {
ll tmp = p[i].first;
for(int j = 1; j <= n; ++j)
if((p[j].first | tmp) == tmp)
vis[j] = 1;
}
}
ll ans = 0;
for(int i = 1; i <= n; ++i) {
if(vis[i])
ans += p[i].second;
}
printf("%lld\n", ans);
return;
}
E - Kamil and Making a Stream
一个计数题。