HDU6655 Just Repeat
题意
两个人做游戏,先手有n张牌,后手有m张牌,每张牌有一种颜色,两人轮流出牌,当一个人出了一种颜色的牌之后,另一个人就不能出相同颜色的牌了,如果一个人无牌可出则输掉游戏。分别给出n张牌和m张牌的颜色,求赢家。
题目连接
思路
对于一个人有而另一个人没有的颜色可以不予考虑。到此为止, 问题转换成另一个问题,就是有一堆东西,每个东西有两个值,A 拿到这个东西的收益是 ai,B 拿到的收益是 bi。两人依次拿,求最优策略下两人的各自收益。解决方法是贪心,按照ai+bi排序,两人轮流拿。用交换法瞎证明一下不知对不对,设两个物品i,j,A取了i,B取了j,剩下的假设按照最优策略取,A得到suma权值,B得到sumb权值,若A取i,B取j的情况优于A取j,B取i。则有suma+ai-sumb-bj>suma+aj-sumb-bi。化简得ai+bi>aj+bj。
代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int maxn = 100000+10;
struct node
{
int a,b;
};
int n,m,p;
ULL k1,k2;
int mo;
int a[maxn],b[maxn];
int tmp[2*maxn];
node c[2*maxn],d[2*maxn];
int ans1,ans2;
int num;
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;
}
bool cmp(node x,node y)
{
return x.a+x.b>y.a+y.b;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d",&n,&m,&p);
if (p==1)
{
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=m;i++) scanf("%d",&b[i]);
} else
{
scanf("%llu%llu%d",&k1,&k2,&mo);
for (int i=1;i<=n;i++) a[i]=rng()%mo;
scanf("%llu%llu%d",&k1,&k2,&mo);
for (int i=1;i<=m;i++) b[i]=rng()%mo;
}
int nn=0;
for (int i=1;i<=n;i++) tmp[++nn]=a[i];
for (int i=1;i<=m;i++) tmp[++nn]=b[i];
sort(tmp+1,tmp+nn+1);
nn=unique(tmp+1,tmp+nn+1)-tmp-1;
for (int i=1;i<=nn;i++) c[i].a=c[i].b=0;
for (int i=1;i<=n;i++)
{
int pos=lower_bound(tmp+1,tmp+nn+1,a[i])-tmp;
c[pos].a++;
}
for (int i=1;i<=m;i++)
{
int pos=lower_bound(tmp+1,tmp+nn+1,b[i])-tmp;
c[pos].b++;
}
ans1=ans2=0;
num=0;
for (int i=1;i<=nn;i++)
{
if (c[i].a==0)
{
ans2+=c[i].b;
} else
if (c[i].b==0)
{
ans1+=c[i].a;
} else
{
num++;
d[num]=c[i];
}
}
sort(d+1,d+num+1,cmp);
for (int i=1;i<=num;i++)
{
if (i%2) ans1+=d[i].a; else ans2+=d[i].b;
}
if (ans1>ans2) printf("Cuber QQ\n"); else printf("Quber CC\n");
}
return 0;
}