题解 时之终结
题目描述
具体做法与心路历程
这是一道简单的构造题。因为要使点数尽量少,那么我们边可以尽可能多的连。
- 若只有一个点,那么最多有 0 0 0条路径。
- 若有两个点,那么最多有 1 1 1条路径。
- 若有三个点,那么最多有 2 2 2条路径。
- 若有四个点,那么最多有 4 4 4条路径。
- …
可以发现,若有 n n n个点,那么当前点最多有 2 n − 2 2^{n-2} 2n−2条路径( n = 1 n=1 n=1为 0 0 0条。
那么我们可以把 Y Y Y表示成二进制,然后直接用 1 1 1号点拼出即可。
C o d e \mathcal{Code} Code
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月22日 星期二 08时20分37秒
*******************************/
#include<cstdio>
#include<algorithm>
using namespace std;
struct IO{
template<typename T>
IO & operator>>(T&res)
{
T q=1;char ch;
while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
res=(ch^48);
while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
res*=q;
return *this;
}
}cin;
long long Y;
int n,m,cnt[70],k,num;
inline void add(int u,int v) { printf("%d %d\n",u,v); }
int main()
{
//freopen("review.in","r",stdin);
//freopen("review.out","w",stdout);
cin>>Y;
if(Y==0){ printf("1 0\n"); return 0;}
long long s=Y,t=1;
while(s)
{
++t;
if(s&1)
cnt[t]++,k++;
s>>=1;
}
printf("%lld %lld\n",t+1,(t-1)*t/2+k);
for(int i=t+1;i>=2;i--)
for(int j=i+1;j<=t+1;j++)
add(i,j);
add(1,2);
for(int i=t-1;i>=1;i--)
if(cnt[i])
{
add(1,t+2-i);
}
return 0;
}