题目:点击打开链接
题意:给出一个K(1~1e6),要求构造一个图G满足一下条件:75个点以内,不存在重边,且刚好存在K个(4点完全图).
分析:构造好题,首先看到这道题都会先暴力跑一波C(n,4),因为这是n个点的完全图存在4点完全图的数量,观察发现当n>=72时C(n,4)才大于1e6我的做法是先取一个K以内的最大T个点的完全图,然后剩下的数量就是K-C(T,4),还有一点可以发现就是对于一个点加入一个完全图时,对答案K上的贡献是C(x,3),这里的x是该点与完全图内任意点连边的数量,T_max=71,我就猜想是否能够取最少剩下的4个点加入T个点的完全图中从而凑出K,评测机证明了我的猜想是错误的,没想到利用背包的思想。(取5个点(T的最大值变为70),从而能够凑出1e6以内的所有K.(证明可以用背包))
题解:
• 构造一个大小为t的完全图,和a, b, c, d, e五个点。
• a, b, c, d, e五个点之间没有边,他们只会向t个点连边。
• 如果连了x个,构成C(x, 3)个大小为4的团。
• 找到最大的t,枚举a,b,c,d,计算e。
• 也可以直接背包,并且记录方案。
• 时间复杂度70^4或者是背包复杂度
代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define PI acos(-1.0)
typedef pair<int,int> PII;
const ll mod = 1e9+7;
const int N = 1e6+10;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qp(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int f[N];
int C_3(int n)
{
return (n - 2)*(n - 1)*n / 6;
}
int C_4(int n)
{
return (n - 3)*(n - 2)*(n - 1)*n / 24;
}
void print(int t, int a, int b, int c, int d,int e)
{
printf("%d %d\n", t + 5, t*(t - 1) / 2 + a + b + c + d + e);
for (int i = 1; i <= t; i++)
for (int j = i + 1; j <= t; j++) printf("%d %d\n", i, j);
for (int i = 1; i <= a; i++) printf("%d %d\n", i, t + 1);
for (int i = 1; i <= b; i++) printf("%d %d\n", i, t + 2);
for (int i = 1; i <= c; i++) printf("%d %d\n", i, t + 3);
for (int i = 1; i <= d; i++) printf("%d %d\n", i, t + 4);
for (int i = 1; i <= e; i++) printf("%d %d\n", i, t + 5);
}
int main()
{
int k, t = 4;
scanf("%d", &k);
while (C_4(t) <= k)t++;
t--;
if (t > 70)t = 70;
k -= C_4(t);
for (int i = 2; i <= 70; i++) f[C_3(i)] = i;
for (int a = 2; a <= t; a++)
for (int b = a; b <= t; b++)
for (int c = b; c <= t; c++)
for (int d = c; d <= t; d++)
{
int cnt = C_3(a) + C_3(b) + C_3(c) + C_3(d);
if (cnt > k)break;
if (f[k - cnt])
{
print(t, a, b, c, d, f[k - cnt]);
return 0;
}
}
}