題目鏈接: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;
}