[HDU6655-2019杭电多校第七场1010] Just Repeat

 传送门:Just Repeat

题意大概是,a、b手中各有带有颜色的n、m张牌,a先手,双方轮流出牌,一方出过的颜色,对方不可出,无法出牌者败。那么,双方优先出的牌的颜色,一定是场上还没出过、对方同样持有且双方持有总数最大的,因为这样,就能保证自己能够出更多的牌或能让对方少出更多的牌,从而增大胜算。所以,只要统计双方都有的颜色的牌的总数,按照数量逆序排序,从a开始轮流分配,即表明该颜色是该方可打出的,最后统计双方可打出的牌的数量,如果a可打出的牌数大于b,则a胜,否则b胜。

#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+5;
int t, n, m, p, mod;
ull k1, k2;
int a[maxn], b[maxn];
typedef pair<int, int> PAIR; //用于vector,方便map排序的type
bool cmp(const PAIR& x, const PAIR& y){ //map转化为vector后,按值排序的cmp函数
    if(x.second != y.second)
        return x.second > y.second;
    return x.first < y.first;
}

ull rng() {
    ull k3 = k1, k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}

void read(){
    cin >> n >> m >> p;
    if(p == 1){
        for(int i = 0; i < n; ++i)
            cin >> a[i];
        for(int i = 0; i < m; ++i)
            cin >> b[i];
    }else{
        cin >> k1 >> k2 >> mod;
        for (int i = 0; i < n; ++i)
            a[i] = rng() % mod;
        cin >> k1 >> k2 >> mod;
        for (int i = 0; i < m; ++i)
            b[i] = rng() % mod;
    }
}

void solve(){
    unordered_map<int, int> ma, mb, mc; //ma、mb:a、b都有的颜色中两者分别持有的数量;mc:ma[i]+mb[i],作为排序的权重。用unordered_map速度更快
    int ln = n, lm = 0; //a、b剔除都有的颜色的手牌后,剩余的手牌数量,也就是单独所有的颜色的总数量。这里的初始化不同是因为后续计算方式不同
    for(int i = 0; i < n; ++i){
        if(!ma.count(a[i])) ma[a[i]] = 1; //如果当前颜色尚未记录,则置为1
        else ++ma[a[i]]; //否则累加,计算持有的数量
    }
    for(int i = 0; i < m; ++i){
        if(!ma.count(b[i])) ++lm; //如果a的手牌中没有b[i]的颜色,说明b[i]的颜色为b单独所有
        else if(!mc.count(b[i])){ //否则说明a的手牌中也有b[i]的颜色
            ln -= ma[b[i]]; //此时,由于b[i]颜色并非a所独有,所以要减去a持有b[i]颜色的手牌数,得到a单独所有的颜色的总数
            mb[b[i]] = 1; //表明b持有a也有的颜色的手牌
            mc[b[i]] = ma[b[i]]+1; //计算某个a、b都有的颜色的总数
        }else{
            ++mb[b[i]];
            ++mc[b[i]];
        }
    }
    vector<PAIR> vec(mc.begin(), mc.end()); //将map转化为vector,方便排序
    sort(vec.begin(), vec.end(), cmp); //按值排序,也就是按照a、b都有的各个不同颜色的数量排序
    bool flag = 1; //标记此时轮到a
    for(vector<PAIR>::iterator it = vec.begin(); it != vec.end(); ++it){ //从牌的数量从大到小轮流分配
        int index = (*it).first;
        if(flag) ln += ma[index]; //轮到a
        else lm += mb[index]; //轮到b
        flag = !flag;
    }
    if(ln > lm) cout << "Cuber QQ\n"; //a的手牌更多,则a赢
    else cout << "Quber CC\n"; //否则b赢
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> t;
    while(t--){
        read();
        solve();
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值