牛课第七场 E Counting 4-Cliques(构造)

传送门

思路:对于n个点的完全图,有C(n,4)个,我们需要先枚举第一个小于k的完全图(但是需要和70取最小值,否则剩下的点可能构造剩下的数不够),然后还剩下k-C(n,4)个,我们每添加一个点,向完全图连接n2条边, 会增加C(n2,3)个,我们可以用背包dp这个值,使得使用的点最少。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int f[100][5];
int dp[N], choice[N];

void init(){
    for(int i=3; i<=75; i++){
        f[i][3]=i*(i-1)*(i-2)/6;
        if(i>3)
            f[i][4]=i*(i-1)*(i-2)*(i-3)/24;
    }
}
int k;
int main(){
    init();
    scanf("%d", &k);
    int n1=4, n2=0;
    while(f[n1][4]<=k)n1++;
    n1--;
    n1=min(n1, 70);
    k-=f[n1][4];
    for(int i=1; i<=k; i++) dp[i]=0x3f3f3f3f;
    dp[0]=0;
    for(int i=3; i<=n1; i++){
        for(int j=f[i][3]; j<=k; j++){
            if(dp[j]>dp[j-f[i][3]]+1){
                dp[j]=dp[j-f[i][3]]+1;
                choice[j]=i;
            }
        }
    }
    int e=n1*(n1-1)/2;
    int tmp=k;
    while(tmp){
        e+=choice[tmp];
        n2++;
        tmp-=f[choice[tmp]][3];
    }


    printf("%d %d\n", n1+n2, e);

    for(int i=1; i<=n1; i++){
        for(int j=i+1; j<=n1; j++)
            printf("%d %d\n", i, j);
    }

    for(int i=n1+1; i<=n1+n2; i++){
        for(int j=1; j<=choice[k]; j++)
            printf("%d %d\n", i, j);
        k-=f[choice[k]][3];
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/du_lun/article/details/81544385
今日推荐