2020智算之道复赛 C - 有向无环图(思维+二进制拆分)

2020智算之道复赛 C - 有向无环图(思维+二进制拆分)_第1张图片
首先最重要的一点是要知道图如何去画,以四个点为例,一般也许会画上下左右四个点的图,但是这样的话很难发现规律,实际上因为是有向无环图,那么我们考虑所有节点排成一条链,然后像找任意两点间的连线那样考虑,如下图所示:
2020智算之道复赛 C - 有向无环图(思维+二进制拆分)_第2张图片
很容易发现以下规律,设 x x x为图的点数, y y y为路径数:

  • x = 2 x=2 x=2时, y = 1 y=1 y=1
  • x = 3 x=3 x=3时, y = 2 y=2 y=2
  • x = 4 x=4 x=4时, y = 4 y=4 y=4
  • x = 5 x=5 x=5时, y = 8 y=8 y=8

那么得到,当图有 x x x个节点时,路径数为 2 x − 2 2^{x-2} 2x2

如果先拿出 x x x个节点,先连成一条链,然后将除一号节点外的所有节点向后面的 x − i − 1 x-i-1 xi1个节点连接,那么路径数为 2 x − 3 2^{x-3} 2x3条,然后我们将一号节点依次连向第 x , x − 1 , x − 2 , . . . , 3 x,x-1,x-2,...,3 x,x1,x2,...,3个节点时,增加的路径数分别为 1 , 1 , 2 , 4 , 8 , . . . 1,1,2,4,8,... 1,1,2,4,8,...,很容易联想到二进制拆分。

假设需要 k k k条路径,先找到大于等于 k k k的第一个 2 2 2的次幂 x x x,那么显然顶点总数为 m = x + 2 m=x+2 m=x+2,然后按上述第一个步骤连接。接下来看看余数是否为0,如果为0那么恰好需要一号顶点向 3 , 4 , 5... , m 3,4,5...,m 3,4,5...,m相连,否则我们对余数 r e s res res二进制拆分,实际上就是看某一位是否为 1 1 1,然后从第 m − 1 m-1 m1个节点开始作为最低位,如果该数二进制位为 1 1 1依次加边,最后输出即可

注意最大可能找到 1 < < 64 1<<64 1<<64恰好爆 u n s i g n e d    l o n g    l o n g unsigned ~~long ~~long unsigned  long  long,那么使用 _ _ i n t 128 \_\_int128 __int128

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const double dinf=1e300;
const ll INF=1e18;
const int Mod=1e9+7;
const int maxn=2e5+10;

vector<pii> ans;

void write(__int128 x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    ull k,n;
    cin>>k>>n;
    if(k==1){
        cout<<"2 1\n1 2\n";
        return 0;
    }
    if(k==2){
        cout<<"3 3\n1 2\n2 3\n1 3\n";
        return 0;
    }
    __int128 one=1;
    ull x=0,m;
    while((one<<x)<k) x++;
    //cout<<"x:"; write(x); cout<
    
    m=x+2;
    ans.push_back({1,2});
    ans.push_back({m-1,m});
    for(int i=2;i<=m-2;i++){
        for(int j=i+1;j<=m;j++)
            ans.push_back({i,j});
    }
    
    ull res,p;
    if((one<<x)==k) res=0;
    else res=(ull)((__int128)k-(one<<(x-1)));
    //cout<<"res:"<
    
    vector<int> tmp;
    p=res;
    while(res){
        if(res&1) tmp.push_back(1);
        else tmp.push_back(0);
        res>>=1;
    }
    
    //cout<<"binary:"; for(auto i: tmp) cout<
    if(p){
        for(int i=0,j=m-1;i<tmp.size();i++,j--) if(tmp[i]){
            ans.push_back({1,j});
        }  
    }else{
        for(int i=3;i<=m;i++) ans.push_back({1,i});
    }
   
    cout<<m<<" "<<ans.size()<<"\n";
    for(int i=0;i<ans.size();i++) cout<<ans[i].first<<" "<<ans[i].second<<"\n";
    return 0;
}

你可能感兴趣的:(Other,Contests)