题解:P14478 手心
Cosmos_zzx · · 题解
本题真的是黄吗?(蒟蒻不会,代码不长但细节多,对于才学最大独立集的OIER比较难想)。
思路
最大
我们先来看最大值怎么求。
因为
所以,我们转而思考,最大独立集是一个集合,根据最大独立集的定义,最大独立集中的点两两不直接联通,我们可不可以枚举最大独立集的点数,让其他点连向它们?这样的话也符合最大独立集的定义。
可是,这样做有个问题,我们无法确定这个最大独立集是否是这种连边中最大的,除非其他点构成一个完全图。
我们可以转而想到枚举完全图的点的个数,其他点便成为了一个最大独立集。
所以,这种方法直接又好求,唯一的问题就是
最小
最小值比较难想。
我们来看一个问题:
把一个
n=12 的点集分成两个完全图,转化成11,1 好还是转化成6,6 好(每个数字是每个完全图的大小)?显然是后者,每个完全图只能贡献一个点,而后者显然是在满足条件下所需边数最小的方案。
为什么不用求最大值的方法?因为求最大值只是枚举一个完全图,其他点都是最大独立集中的一个,肯定没有分成几个完全图贡献的少。
这里也是用二分枚举分成几个完全图,对于一组一组分后剩下的那些点(也就是
代码
#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;
}