P5815 [CQOI2010]扑克牌 题解

这篇博客介绍了如何运用二分搜索算法解决CQOI竞赛中的一道题目。博主详细阐述了正确性证明,指出由于问题的单调性,已找到的解一定是下界。在二分搜索过程中,博主给出了check函数的分析,解释了如何判断当前解是否可行,并特别注意了在二分模板中的边界条件,以避免死循环。最后,博主提供了ACCode,即通过测试的代码实现。
摘要由CSDN通过智能技术生成

首先,我是从一本通那儿过来的,但因为数据范围不同,所以正解代码就不同,那里 n 极其大,但这里确是 c_i 极其大,所以我们必须二分答案。代码不难,但是细节比较多。作为一名 CQ OIer,感触较深。

正确性证明

首先,我们因为要求最优解,所以说我们可以来证明一下,如果已经求出的解为 $ans$,那么答案一定大于等于它,因为这个解已经成立了,不可能取比它小的了,所以满足了单调性。

二分方法

首先,左端点为 0,表示一个都不能成套,最大区间为 $7.5\times 10^8$。最坏数据如下:

2 500000000
500000000 500000000 500000000


此时答案为 7.5\times 10^8,如果不会算,设成 10^9 也无妨。

二分的 check 函数可以这样来分析:

首先,设当前判断的是 x,那么我们就可以这样想:如果它的牌本来就够,那么就用它自己的,把 joker 给其他牌,这样一定能满足,如果给了它,冗余的也没用,所以我们加上的就是 c_i-x,但是我们不能让它变为负数,所以说还要与就求不够的牌数,但是它肯定是自然数,所以还要和 0 取最大值,这就是它缺少的。一共进行 x 轮,每次最多补一个,在保证足够的情况下,一共只能补 k=\min{m,x} 次,所以记录 t 为缺少牌的数量,然后如果 t\le k,那么可以取 x 次,返回 1,否则返回 0。

有了详细的二分,我们只需要套个二分模板,但要注意的是,区间终点必须偏右,否则只有 40 分,原因如下:

首先,但判断到最后一次时,l=r-1,此时 mid=\frac{l+r}{2}=l,如果成立,那么 l=mid 一直执行下去,即一直满足 l<r,等死恒成立,二分不会退出,就会变成死循环,所以说我们在最后一次时区间终点必须偏右。

AC Code:

#include<bits/stdc++.h>
#define int long long //t有可能爆 int
using namespace std;
int n,a[55],m,l,r=7.5e8;//l 左端点,r 右端点
bool check(int x){
    int t=0;
    for(int i=1;i<=n;i++){
        t+=max(x-a[i],0ll);//累加缺少的牌数
        if(t>min(x,m))
            return 0;//如果不够就不行
    }
    return 1;//判断到最后都可以就是可行的
}
signed main(){
    scanf("%lld %lld",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    while(l<r){
        int mid=l+r>>1;
        if(l==r-1)
            mid++;//向上取整,否则40分
        if(check(mid))
            l=mid;
        else
            r=mid-1;//左边可以取,右边不能取
    }//二分模板
    printf("%lld\n",r);//取当前的右端点
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有 $n$ 个人,每个人有一个编号 $i$,每个人都跳舞,但是每个人都只会一种舞蹈。现在要求他们排成一个圆圈跳舞,使得相邻两个人跳的舞蹈不同。求方案数。 输入格式 一个整数 $n$。 输出格式 一个整数,表示方案数,由于答案可能很大,输出对 $10^9+7$ 取模的结果。 数据范围 $1\leq n\leq 10^5$ 输入样例1: 5 输出样例1: 20 输入样例2: 10 输出样例2: 14684570 算法 数学,组合数学,动态规划 思路 题目要求的是排成一个圆圈跳舞,而且相邻两个人跳舞的舞蹈不同,这就意味着最后一个人的舞蹈类型必须和第一个人不同。因为它们是相邻的。 如果我们考虑将最后一个人的舞蹈类型和第一个人不同的方案数,那么实际上就是将 $n$ 个人分成两组: - 第一组是前 $n-1$ 个人,需要满足相邻两个人跳舞的舞蹈不同。 - 第二组是第 $n$ 个人,需要满足和第一个人跳舞的舞蹈不同。 对于第一组,我们可以定义 $f[i]$ 表示前 $i$ 个人,最后一个人和第一个人跳舞的舞蹈类型不同的方案数。因为需要满足相邻两个人跳舞的舞蹈不同,所以有两种情况: - 如果第 $i$ 个人和第 $i-1$ 个人跳舞的舞蹈类型不同,那么最后一个人的舞蹈类型可以是除了第 $i-1$ 个人和第一个人外的所有舞蹈类型,即共有 $n-2$ 种选择。 - 如果第 $i$ 个人和第 $i-1$ 个人跳舞的舞蹈类型相同,那么最后一个人的舞蹈类型只能是第 $i-1$ 个人和第一个人的舞蹈类型中的一种,即共有 $2$ 种选择。 综上所述,递推式为: $$f[i]=\begin{cases} (n-2)\times f[i-1] + 2\times f[i-2], & a[i]\neq a[i-1] \\ (n-1)\times f[i-1], & a[i]=a[i-1] \end{cases}$$ 对于第二组,最后一个人的舞蹈类型只能是除了第一个人的所有舞蹈类型,即共有 $n-1$ 种选择。 因此我们可以得到最终的方案数: $$ans=(n-1)\times f[n-1]$$ 代码 时间复杂度 $O(n)$ 空间复杂度 $O(n)$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值