专栏文章

题解:P14478 手心

P14478题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min7xutb
此快照首次捕获于
2025/12/01 22:02
3 个月前
此快照最后确认于
2025/12/01 22:02
3 个月前
查看原文
本题真的是黄吗?(蒟蒻不会,代码不长但细节多,对于才学最大独立集的OIER比较难想)。

思路

最大

我们先来看最大值怎么求。
因为 1n1091\leq n \leq 10^9,所以尝试构造解再求最大独立集的想法是不现实的。
所以,我们转而思考,最大独立是一个集合,根据最大独立集的定义,最大独立集中的点两两不直接联通,我们可不可以枚举最大独立集的点数,让其他点连向它们?这样的话也符合最大独立集的定义。
可是,这样做有个问题,我们无法确定这个最大独立集是否是这种连边中最大的,除非其他点构成一个完全图
我们可以转而想到枚举完全图的点的个数,其他点便成为了一个最大独立集
所以,这种方法直接又好求,唯一的问题就是 1n1091\leq n \leq 10^9,直接枚举大小不现实,容易想到可以二分解决。

最小

最小值比较难想。
我们来看一个问题:
把一个 n=12n=12 的点集分成两个完全图,转化成 11,111,1 好还是转化成 6,66,6 好(每个数字是每个完全图的大小)?
显然是后者,每个完全图只能贡献一个点,而后者显然是在满足条件下所需边数最小的方案。
为什么不用求最大值的方法?因为求最大值只是枚举一个完全图,其他点都是最大独立集中的一个,肯定没有分成几个完全图贡献的少。
这里也是用二分枚举分成几个完全图,对于一组一组分后剩下的那些点(也就是 nmodmid,midn\bmod mid,mid 是分成的完全图个数),直接平均分到所有完全图中即可。

代码

CPP
#include<bits/stdc++.h>
#define int long long
typedef long long ll;
using namespace std;
const int N=2e5+114;
int T,n,m;
signed main()
{
    cin>>T;
    while(T--)
    {
        cin>>n>>m;
        if(m==0)
        {
            cout<<n<<" "<<n<<endl;
            continue;
        }
        int l=1,r=n;
        int mid=0,ans=0;
        while(l<=r)
        {
            mid=l+r>>1;
            if(mid*(mid-1)/2+(n-mid)*(mid-1)>=m)ans=mid,r=mid-1;
            else l=mid+1;
        }
        cout<<n-ans+1<<" ";//最大
        ans=0,l=1,r=n;
        while(l<=r)
        {
            mid=l+r>>1;
            if((n/mid)*(n/mid-1)*(mid-n%mid)/2+(1+n/mid)*(n/mid)/2*(n%mid)<=m)ans=mid,r=mid-1;
            else l=mid+1;
        }
        cout<<ans<<endl;//最小
    }
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...