题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6655
题目大意:两个人打牌,每人手里各种颜色牌若干张,每次出一张,打牌规则是:若某种颜色的牌出手了,则对方不能出这种颜色的牌,最后不能出牌者输。
题解思路:
每个人优先出的牌的颜色肯定是场上没出过的, 对方也持有的, 并且两个人手中持有数量最多的牌,这是因为对方持有的越多意味着可以封掉更多的牌, 而自己手里的越多意味着可以防止自己更多的牌被封掉.
因此, 对所有两个人手里都持有的颜色的牌数进行统计, 从大到小依次分配给第一, 第二个玩家. 如果此时第一个玩家手里的牌数 第二个玩家, 则第一个玩家胜利, 否则第二个玩家胜利. 到此为止, 问题转换成另一个问题, 就是有一堆东西, 每个东西有两个值, 玩家拿到这个东西的收 益是 , 玩家 拿到的收益是 .两人依次拿.求最优策略下两人的各自收益.这是一个经典问题, 答案就是按照 排序模拟一下就好了.
AC代码:
#include<bits/stdc++.h>
using namespace std;
unsigned long long n,m,p,a[100010],b[100010];
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;
}
void ger1(){
for (int i = 0; i < n; ++i){
a[i] = rng() % mod;
}
}
void ger2(){
for (int i = 0; i < m; ++i){
b[i] = rng() % mod;
}
}
int ca,cb;
using pp = pair<unsigned long long, int>;
bool cmp(pp x,pp y){//sum重载的是按照这种牌的总数从大到小排序
return x.first+x.second>y.first+y.second;
}
pp cnta[100010],cntb[100010];//cnta表示QQ手中每种牌对应的颜色和数量,cntb表示CC手中每种牌对应的颜色和数量
pp sum[100010];//sum表示每种牌的总数从大到小排序,first对应的是QQ手中这种牌的数量,second对应的是CC手中这种牌的数量
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%llu%llu%llu",&n,&m,&p);
if(p==1){
for(int i=0;i<n;i++){
scanf("%llu",&a[i]);
}
for(int i=0;i<m;i++){
scanf("%llu",&b[i]);
}
}
else{
scanf("%llu%llu%llu",&k1,&k2,&mod);
ger1();
scanf("%llu%llu%llu",&k1,&k2,&mod);
ger2();
}
sort(a,a+n);//先对a,b进行排序,使得相同颜色的牌相邻,方便后续对每种牌计数操作
sort(b,b+m);
ca=0,cb=0;//ca表示QQ手中实际牌的种类,cb表示CC手中实际牌的种类
int i=1,la=0;
while(i<n){
while(i<n&&a[i]==a[i-1]){
i++;
}
cnta[ca++]=pp(a[la],i-la);
la=i;
i++;
}
if(a[n-1]!=a[n-2]){
cnta[ca++]=pp(a[n-1],1);
}
int j=1,lb=0;
while(j<m){
while(j<m&&b[j]==b[j-1]){
j++;
}
cntb[cb++]=pp(b[lb],j-lb);
lb=j;
j++;
}
if(b[m-1]!=b[m-2]){
cntb[cb++]=pp(b[m-1],1);
}
int qs=0,cs=0;//打牌时qs表示QQ手中可出的牌的数量,cs表示CC手中可出的牌的数量
int csum=0;
for(int ii=0,jj=0;ii<ca||jj<cb;){
if(ii<ca&&jj<cb&&cnta[ii].first==cntb[jj].first){
sum[csum++]=pp(cnta[ii++].second,cntb[jj++].second);//将相同颜色牌计入到sum中
}
else if(ii==ca||(jj<cb&&cntb[jj].first<cnta[ii].first)){
cs+=cntb[jj++].second;//QQ手里没牌了,那么此时CC手里的牌都是自己的
}
else{
qs+=cnta[ii++].second;//CC手里没牌了,那么此时QQ手里的牌都是自己的
}
}
sort(sum,sum+csum,cmp);//对sum进行总数排序
for(int k=0;k<csum;k++){
if(k%2==0){
qs+=sum[k].first;//QQ、CC每次都先拿剩下牌中总数最多的牌,这样保证最优,但是QQ先拿
}
else{
cs+=sum[k].second;
}
}
if(qs>cs){
printf("Cuber QQ\n");
}
else{
printf("Quber CC\n");
}
}
return 0;
}