Description
要求构造一个不超过 75 75 75个点的无向图使得该图的四元团个数恰好为 k k k个
Input
一个整数 k ( 1 ≤ k ≤ 1 0 6 ) k(1\le k\le 10^6) k(1≤k≤106)
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 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,枚举这三个集合及其交集点数使得加入这三个点的贡献等于剩余四元团个数即可
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;
}