构造——cf1311E好题

/*
对于每个n,满足条件的d总是在一段区间内
d的最小值就是完全二叉树的dmin,最大值是链的dmax 
[dmin,dmax]这段区间内的所有值都可以取到    
    策略:先构造一棵n个点的完全二叉树,自底层向上判断,每次只把一个可以往下挪的点往下挪
    这样每次d只会+1
*/
#include<bits/stdc++.h>
using namespace std;
#define N 5005
int num[N],h;
int main(){
    int t;cin>>t;
    while(t--){
        h=0;
        memset(num,0,sizeof num);
        int n,d;
        cin>>n>>d;
        
        int dmin=0,dmax=0;
        int tmp=n;
        while(tmp){
            h++;
            if(tmp>=(1<<(h-1))){
                tmp-=(1<<(h-1));
                dmin+=(1<<(h-1))*(h-1);
                num[h]=(1<<(h-1));
            }else {
                dmin+=tmp*(h-1);
                num[h]=tmp;
                tmp=0;
            }
        }
        for(int i=1;i<=n;i++)dmax+=i-1;
        if(d<dmin || d>dmax){puts("NO");continue;}
        
        d-=dmin;
        while(d){
            d--;
            for(int i=h+1;i>=2;i--){
                if(num[i]+1<=2*(num[i-1]-1)){
                    num[i]++;
                    num[i-1]--;
                    if(i==h+1)h=i;
                    break;
                }
            }
        }
        puts("YES");
        int now=1;
        for(int i=2;i<=h;i++){
            for(int j=1;j<=num[i];j++)
                cout<<now+(j+1)/2-1<<" ";
            now+=num[i-1];
        }
        puts("");
    }
} 
/*
对于每个n,满足条件的d总是在一段区间内
d的最小值就是完全二叉树的dmin,最大值是链的dmax 
[dmin,dmax]这段区间内的所有值都可以取到    
    策略:先构造一棵n个点的完全二叉树,自底层向上判断,每次只把一个可以往下挪的点往下挪
    这样每次d只会+1
*/
#include<bits/stdc++.h>
using namespace std;
#define N 5005
int num[N],h;
int main(){
    int t;cin>>t;
    while(t--){
        h=0;
        memset(num,0,sizeof num);
        int n,d;
        cin>>n>>d;
        
        int dmin=0,dmax=0;
        int tmp=n;
        while(tmp){
            h++;
            if(tmp>=(1<<(h-1))){
                tmp-=(1<<(h-1));
                dmin+=(1<<(h-1))*(h-1);
                num[h]=(1<<(h-1));
            }else {
                dmin+=tmp*(h-1);
                num[h]=tmp;
                tmp=0;
            }
        }
        for(int i=1;i<=n;i++)dmax+=i-1;
        if(d<dmin || d>dmax){puts("NO");continue;}
        
        d-=dmin;
        while(d){
            d--;
            for(int i=h+1;i>=2;i--){
                if(num[i]+1<=2*(num[i-1]-1)){
                    num[i]++;
                    num[i-1]--;
                    if(i==h+1)h=i;
                    break;
                }
            }
        }
        puts("YES");
        int now=1;
        for(int i=2;i<=h;i++){
            for(int j=1;j<=num[i];j++)
                cout<<now+(j+1)/2-1<<" ";
            now+=num[i-1];
        }
        puts("");
    }
} 
原文地址:https://www.cnblogs.com/zsben991126/p/12487634.html