H题的题解

H题题解

链接:题目

题目大意:给你一个数L,让你用最多20个点,60条边建立一个有向图,让从1到n的不同路径恰好为L,且值分布为0-L-1。
要求:可以有重边但不能有自环,边都是由小指向大的。
L的范围: 2 ≤ L ≤ 1 0 6 2\leq L\leq 10^{6} 2L106
解析:首先我们想到用二进制去思考这个问题, 2 20 2^{20} 220刚好是1e6,然后对于这个题意我们就能用38条边去表示每一位取不取,即假设点20为1,19为2,18为4……,1为 2 19 2^{19} 219,然后对于每个点都往后连一条0和一条值为后面点权值的边表示不取和取。其中会发现点1没有取的边,这个后面能处理。
接下来就是类似用数位dp处理0到n有多少个数的思想处理这个问题。

对于一个二进制为101101的数,我们从点15到点20连边,然后从前往后对于每一位是1的数我们考虑这个位置取0和取1的情况。比如第1个1,也就是点15,取0那么后面的数就可以任意选,所以我们就可以从点1往点15连一条值为0的边,取1的情况我们先把数用一个he累积下来,继续往下细分,后面的位置如果是0,就取0,到了点17也就第二个1,如果取0那么就可以任意取,我们从点1往点17连值为he的边,也就是前面的位置能取1就取1的情况,取1的情况继续往后推。
显然每个点最多从1连过来一条边,故答案不会超过60.特别需要注意因为这题不能自环,所以1向1连边需要处理掉。
开头我们说点1没有连向他的边,但因为点1永远是首位,他的取0分支的he为0,也就是有他的情况永远在取1分支中,这所有数首位都是如此。故没有问题。

#include<bits/stdc++.h>
using namespace std;
const int N=1<<21;
int main(){
	long long a;
	cin>>a;
	vector<int>t;
	long long b=a;
	int idx=0;
	while(a){
		if(a&1)idx++;
		t.push_back(a%2);
		a/=2;
	}
	idx+=2*(t.size()-1);//特判1 1
	if(b&(1<<19))idx--;
	printf("20 %d\n",idx);
	for(int i=20-t.size()+1;i<20;i++){
		printf("%d %d 0\n",i,i+1);
	}
	for(int i=20-t.size()+1;i<20;i++){
		printf("%d %d %d\n",i,i+1,N>>(i+2));
	}
	long long p=0;
	for(int j=1;j<=20;j++){
		int d=N>>(j+1);
		if(b&d){
			if(j!=1)printf("1 %d %lld\n",j,p);
			p+=d;
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值