[luoguP11323] Happy Card

题意

原题链接
n 种牌,第 i 种牌有 ai 张,每次可以出 1 张(单牌)、2 张(对子)或 4 张相同的牌(四炸),或是 3 张相同的牌及 1 张不同的牌(三带一),求把牌出完最少需要多少次。

sol

赛时看到这道题,就想到了 [luoguP2668]斗地主,由于没有顺子,因此可以直接考虑贪心。
反复审读题意,不难发现,后两种操作方式本质上都是 3 张牌带任意 1 张牌(下统称为三带一),因此处理出将所有相同的牌三个三个出需要出的次数 sum3,以及剩余 1 张及 2 张牌的种数 cnt1,cnt2。然后贪心的取即可。
具体地,需要分类讨论两种情况:

  1. 所有的三张相同的牌可以将剩余的牌全部带出,此时,剩余的牌有以下几种情况:
  • 剩余 1 组三张相同的牌,需要出一个对子及一张单牌,共 2 次;
  • 剩余 2 组三张相同的牌,需要出一个三带一及一个对子,共 2 次;
  • 剩余 3 组三张相同的牌,需要出两个三带一及一张单牌,共 3 次;
  • 剩余 4 组三张相同的牌,需要出三个三带一,共 3 次;
  • 剩余 4 组以上三张相同的牌,贪心地取,每次优先取 4 组三张相同的牌,当不够取时,按上述情况取即可。
  1. 所有的三张相同的牌不可以将剩余的牌全部带出,此时,优先带出剩余 1 张的牌,再优先带出剩余 2 张的牌。

证明比较简单,这里不说。
注意最终结果可能会爆 long long。

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 300005;

int a[N];
int T, n;

int main(){
    scanf("%d", &T);
    while (T -- ){
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
        int cnt1 = 0, cnt2 = 0;
        long long cnt3 = 0;
        for (int i = 1; i <= n; i ++ ){
            cnt3 += a[i] / 3;
            if (a[i] % 3 == 1) cnt1 ++ ;
            if (a[i] % 3 == 2) cnt2 ++ ;
        }

        if (cnt3 >= cnt1 + cnt2 * 2) {
            long long ans = cnt1 + cnt2 * 2 + (cnt3 - cnt1 - 2 * cnt2) / 4 * 3 + (cnt3 - cnt1 - 2 * cnt2) % 4;
            if ((cnt3 - cnt1 - cnt2 * 2) % 4 == 1) ans ++ ;
            printf("%lld\n", ans);
        }
        else {
            long long ans;
            if (cnt3 < cnt1) ans = cnt2 + cnt1;
            else ans = cnt3 + (cnt2 * 2 - (cnt3 - cnt1) + 1) / 2;
            printf("%lld\n", ans);
        }
    }
}
posted @   是一只小蒟蒻呀  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示