题解:
容易想到最后答案都是由若干个
2
2
的次幂加起来的,也就是第个点向第
i+1
i
+
1
个点连
2i−1
2
i
−
1
的边,但是这样只有
2x
2
x
条路径,剩下的
L−2x
L
−
2
x
条怎么办呢?现在我们还剩下
L−2x
L
−
2
x
条路径,注意到前
i
i
个点可以凑出~
2i−1−1
2
i
−
1
−
1
,所以我们这样做:每次先找到一个最大的
y
y
使得,那么找出那个可以凑出
2y
2
y
个数的前缀,向终点连一条对应权值的边。举个例子:(
L=11
L
=
11
)
如下连边,可以凑出
0
0
~:
然后找到
y=1
y
=
1
,那么能凑出
21
2
1
个数的前缀是
1
1
、两个点,接下来的两个数是
8
8
、,所以这样连边:
最后是这样:
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1000010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int L,n=1,m=0,a[22],l=0;
struct Edge{int x,y,d;}e[70];
int main()
{
L=read();
int t=L-1;
for(int i=0;(1<<i)<=t;i++)
{
n++;
t-=(1<<i);
e[++m].x=n-1,e[m].y=n,e[m].d=0;
e[++m].x=n-1,e[m].y=n,e[m].d=(1<<i);
}
t=L;
while(t)a[++l]=(t&1),t>>=1;
int tot=(1<<(l-1));
for(int i=l-1;i;i--)
if(a[i])
{
e[++m].x=i,e[m].y=n,e[m].d=tot;
tot+=(1<<(i-1));
}
printf("%d %d\n",n,m);
for(int i=1;i<=m;i++)printf("%d %d %d\n",e[i].x,e[i].y,e[i].d);
}