Newcoder 145 E.Counting 4-Cliques(构造)

186 篇文章 0 订阅

Description

要求构造一个不超过 75 75 75个点的无向图使得该图的四元团个数恰好为 k k k

Input

一个整数 k ( 1 ≤ k ≤ 1 0 6 ) k(1\le k\le 10^6) k(1k106)

Output

输出两个整数 n , m n,m n,m表示点数和边数,之后 m m m行输出每条边

Sample Input

1

Sample Output

4 6
1 2
1 3
1 4
2 3
2 4
4 3

Solution

直观上显然先构造 s s s个点的完全图形成 C s 4 C_s^4 Cs4个四元团,对于剩余的四元团,每加入一个点然后将该点去之前的 x x x点连边会多出 C x 3 C_x^3 Cx3个四元团,但是这样构造会有一部分结果的点数超过 75 75 75的限制,对于这种不合法的构造,考虑另一种构造,假设加入一个三元团 s + 1 , s + 2 , s + 3 s+1,s+2,s+3 s+1,s+2,s+3,假设这三个点与这 s s s个点所连点集为 X , Y , Z X,Y,Z X,Y,Z,那么加入这三个点的贡献为 C ∣ X ∣ 3 + C ∣ Y ∣ 3 + C ∣ Z ∣ 3 + C ∣ X ∩ Y ∣ 2 + C ∣ X ∩ Z ∣ 2 + C ∣ Y ∩ Z ∣ 2 + C ∣ X ∩ Y ∩ Z ∣ 1 C_{|X|}^3+C_{|Y|}^3+C_{|Z|}^3+C_{|X\cap Y|}^2+C_{|X\cap Z|}^2+C_{|Y\cap Z|}^2+C_{|X\cap Y\cap Z|}^1 CX3+CY3+CZ3+CXY2+CXZ2+CYZ2+CXYZ1,枚举这三个集合及其交集点数使得加入这三个点的贡献等于剩余四元团个数即可

Code

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
int C(int n,int k)
{
	if(k==1)return n;
	if(k==2)return n*(n-1)/2;
	if(k==3)return n*(n-1)*(n-2)/6;
	return n*(n-1)*(n-2)*(n-3)/24;
}
vector<P>v;
int check(int k)
{
	for(int n=4;n<=72;n++)
	for(int a1=0;a1<=n;a1++)	
	for(int a2=0;a1+a2<=n;a2++)
	for(int a3=0;a1+a2+a3<=n;a3++)
	for(int a4=0;a1+a2+a3+a4<=n;a4++)
	for(int a5=0;a1+a2+a3+a4+a5<=n;a5++)
	{
		int res=C(n,4)+C(a1+a2+a3,3)+C(a2+a3+a4,3)+C(a3+a4+a5,3);
		res+=C(a2+a3,2)+C(a3+a4,2)+C(a3,2)+C(a3,1);
		if(res==k)
		{
			v.clear();
			for(int i=1;i<=n;i++)
				for(int j=i+1;j<=n;j++)
					v.push_back(P(i,j));
			for(int i=n+1;i<=n+3;i++)
				for(int j=i+1;j<=n+3;j++)
					v.push_back(P(i,j));
			for(int i=1;i<=a1+a2+a3;i++)v.push_back(P(i,n+1));
			for(int i=1;i<=a2+a3+a4;i++)v.push_back(P(i+a1,n+2));
			for(int i=1;i<=a3+a4+a5;i++)v.push_back(P(i+a1+a2,n+3));
			return n+3;
		}
	}				
	return 0;
}
int main()
{
	int n,k,kk;
	scanf("%d",&k);
	kk=k;
	v.clear();
	for(int i=4;i<=75;i++)
		if(C(i,4)>k)
		{
			n=i-1;
			break;
		}
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			v.push_back(P(i,j));
	k-=C(n,4);
	while(k)
	{
		int x;
		for(int j=3;j<=n;j++)
			if(C(j,3)>k)
			{
				x=j-1;
				break;
			}
		k-=C(x,3);
		for(int j=1;j<=x;j++)v.push_back(P(j,n+1));
		n++;
	}
	if(n>75)n=check(kk);
	printf("%d %d\n",n,v.size());
	for(int i=0;i<v.size();i++)printf("%d %d\n",v[i].first,v[i].second);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 8对集合框架进行了一些重大的改进,其中之一就是引入了流式API。在这个新的API中,提供了许多集合操作的新方式。其中一个新特性是groupingBy()方法,它可以根据指定的条件对集合中的元素进行分组。在groupingBy()方法中,可以使用counting()方法来计算每个分组中元素的数量。 在collectors.groupingby(e -> e, collectors.counting())的代码中,collectors是一个类型为Collectors的类。该类提供了用于收集流数据的许多方法,包括groupingBy()和counting()方法。在这个示例中,首先使用groupingBy()方法将元素按照它们自身的值进行分组。然后,使用counting()方法来计算每个分组中元素的数量。 具体而言,这段代码将会从一个流中收集数据。在每个分组中,相同值的元素将会被分到一起。例如,如果流中包含了如下元素:"A", "B", "B", "C", "C", "C"。那么此时使用groupingBy()方法后,将会产生如下的结果: {"A"=["A"], "B"=["B", "B"], "C"=["C", "C", "C"]} 我们可以看到,每个不同的值都被分配到了相应的分组中。然后,我们使用counting()方法来查找每个分组中元素的数量。在这种情况下,我们将会得到这样的结果: {"A"=1, "B"=2, "C"=3} 这里可以看到,每个分组中元素的数量已经被计算出来了。在这个案例中,我们可以看到有一些重复的元素值,但它们被放在一起并且计算了它们的数量。在任何需要对集合中的元素进行分组并计算相关数据的场景下,collectors.groupingby(e -> e, collectors.counting())都是一个非常有用的工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值