二分+高精 牛客小白月赛23 C题 完全图

完全图

题目描述

在图论的数学领域,完全图是一个简单的无向图,其中每对不同的顶点之间都恰连有一条边相连。————百度百科
现在给定一个包含 n 个顶点的完全图,你可以删掉图中的一些边,但是删掉的边不能超过 m 条,请问删去边之后的图最多能有几个连通分量?

输入描述:
第一行包含一个数字 T,表示测试数据组数
接下来 T 行,每行两个正整数n,m,中间用空格隔开
输出描述:
输出 T 行,每行一个整数表示答案


首先要知道无向完全图有 n*(n-1)/2 条边;

然后可以推出规律:

删除边数 连通分量数
n-1 1
n-1+n-2 2
n-1+n-2+n-3 3

所以可以二分枚举连通分量数 x ,算出要删除的边数,然后和 m 比较;

但是这题比较变态的是数据范围,可以采用__int128来代替longlong;

代码:

#include<bits/stdc++.h>
#define LL unsigned long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=100100;
const int M=1000100;
const LL mod=100000000;
inline __int128 read(){//输入模板 
    __int128 x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
inline void print(__int128 x){//输出模板 
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}
__int128 n,m;
int judge(__int128 p){
	__int128 q=p-1;
	__int128 s1=n*q-q*(q+1)/2;
	__int128 s2=s1+n-p;
	if(m<s1) return 0;
	if(s1!=s2&&m>=s1&&m<s2) return 1;
	else if(s1==s2&&m>=s1) return 1;
	return 2;
}
int main(){
	__int128 t=read();
	while(t--){
		n=read(),m=read();
		__int128 l=1,r=n;//二分连通分量 
		__int128 ans=1;
		while(l<=r){
			__int128 d=(l+r)/2;
			int ok=judge(d);
			if(ok==0) r=d-1;
			else if(ok==2) l=d+1; 
			else{
				ans=d;
				break;
			}
		}
		print(ans);
		cout<<endl;
	} 
    return 0;
}

发布了264 篇原创文章 · 获赞 46 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_44291254/article/details/105028573