题意:

Cuber QQ 和 Quber CC 打牌, Q有n张牌, C有m张牌,牌分颜色,每种颜色有若干张,每次你可以打出一张牌后,对方就不能打出相应的颜色的牌,双方的牌都透明可见,在双方足够聪明的情况下,谁先没牌出,谁就输了

题解:

每个人优先出的牌的颜色肯定是场上没出过的, 对方也持有的, 并且两个人手中持有数量最多的牌.对方持有的越多意味着可以封掉更多的牌, 而自己手里的越多意味着可以防止自己更多的牌被封掉.因此, 对所有两个人手里都持有的颜色的牌数进行统计, 从大到小依次分配给第一, 第二个玩家.如果此时第一个玩家手里的牌数 > 第二个玩家, 则第一个玩家胜利, 否则第二个玩家胜利.到此为止, 问题转换成另一个问题, 就是有一堆东西, 每个东西有两个值, A 拿到这个东西的收益是 a i a_i ai, B 拿到的收益是 b i b_i bi.两人依次拿.求最优策略下两人的各自收益.这是一个经典问题, 答案就是按照 a i a_i ai + b i b_i bi 排序模拟一下就好了.

如果你能看懂上面的官方题解,可以不用看我的下面的解释了,因为我一直看不懂上面的说法,现在理解了,于是就写下我一开始不理解的地方~~
我们要优先封掉 对方与自己相同颜色的牌数量最多的那一种,比如我有x张黄色,对方有y张黄色,那么如果我第一个出了黄色牌,那么对方的黄色牌就出不了,比我少出y次牌,而我可以出x次黄牌,那么就相当于我比对方多出了x+y次牌,所以题解的思路就是把双方都有的颜色的牌按照双方的总数量从大到小,给第一个玩家,第二个玩家,然后玩家再加上自己有的牌而对方没有的牌的数量,那么就是双方一共最优策略下最多可以出的牌的数量。

AC_code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;

unsigned long long k1, k2, mod;
unsigned long long rng() {
	unsigned long long k3 = k1, k4 = k2;
	k1 = k4;
	k3 ^= k3 << 23;
	k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
	return k2 + k4;
}
typedef pair<int, int> pii;
pii pa[maxn], pb[maxn], sum[maxn];
bool cmp(pii aa, pii bb){
	return aa.first + aa.second > bb.first + bb.second;
}
int a[maxn];
void read(pii p[], int& nn, int pp) {
	if(pp == 1) {
		for(int i = 0; i < nn; i++) {
			scanf("%d", &a[i]);
		}
	} else {
		scanf("%llu%llu%llu", &k1, &k2, &mod);
		for (int i = 0; i < nn; ++i) {
			a[i] = rng() % mod;
		}
	}
	sort(a, a+nn);
// for(int i = 0; i < nn; i++){
// cout<<a[i]<<endl;
// }
	int mm = 0;
	for(int i = 0, j = 0; i < nn; i = j) {//计算出每一种颜色有多少张 
		for(;(j<nn) && (a[j] == a[i]); ++j);
		p[mm++] = pii(a[i], j-i);
	}
	nn = mm;
}

int main() {
	int t, n, m, p;
	scanf("%d", &t);
	while(t--) {
		scanf("%d%d%d", &n, &m, &p);
		read(pa, n, p);
		read(pb, m, p);
		int qs = 0, cs = 0, k = 0;
		for(int i = 0, j = 0; i < n || j < m; ){
// cout<<i<<" "<<pa[i].first<<" "<< j <<" "<<pb[j].first<<endl;
			if(i < n && j < m && pa[i].first == pb[j].first){//相同颜色的牌 
				sum[k++] = pii(pa[i++].second, pb[j++].second);
			}else if(i == n || (j < m && pb[j].first < pa[i].first)){//CC有的牌 而QQ没有 
				cs += pb[j++].second;
			}else {//QQ有的牌 而CC没有 
				qs += pa[i++].second;
			}
		}
// cout<<qs<<" "<<cs<<endl; 
		sort(sum, sum+k, cmp);
		for(int i = 0; i < k; i++){
			if(i & 1){
				cs += sum[i].second;
			}else {
				qs += sum[i].first;
			}
		}
		if(qs > cs){
			puts("Cuber QQ");
		}else {
			puts("Quber CC");
		}
	}
	return 0;
}