牛客网暑期ACM多校训练营(第七场) E.Counting 4-Cliques (构造)

题目链接

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld

题目描述

You love doing graph theory problems. You've recently stumbled upon a classical problem : Count the number of 4-cliques in an undirected graph.

Given an undirected simple graph G, a 4-clique of G is a set of 4 nodes such that all pairs of nodes in this set are directly connected by an edge.

This task would be too easy for you, wouldn't it? Thus, your task here is to find an undirected simple graph G with exactly k 4-cliques. Can you solve this task?

 

输入描述:

The first line of input contains a single integer k (1 ≤ k ≤ 106).

输出描述:

On the first line, output two space-separated integers, n, m (1 ≤ n ≤ 75, 1 ≤ m ≤ n * (n - 1) / 2). On the next m lines, output two space-separated integers denoting an edge of the graph u, v (1 ≤ u, v ≤ n), where u and v are the endpoints of the edge.

Your graph must not contain any self-loops or multiple edges between the same pair of nodes. Any graph that has exactly k 4-cliques and satisfies the constraints will be accepted. It can be proven that a solution always exist under the given constraints.

 

示例1

输入

1

输出

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

说明

In the sample, the whole graph is a 4-clique.

 

题意:给出一个K(1~1e6),要求构造一个图G满足一下条件:75个点以内,不存在重边,且刚好存在K个(4点完全图).

        要求输出该图G,格式为N,M(N个点,M条边),随后M行为u,v.

题解:很明显是到构造题,首先看到这道题都会先暴力跑一波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.(证明可以用背包)

         不过对于剩5个点我们需要预处理一个点的情况,不然70^5很明显时间复杂度上会爆.

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 1e6+10;
int f[maxn];
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;
                    }
                }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值