[NOIP 2023 模拟7]路程

[NOIP 2023 模拟7]路程

题意:

给一个数字n:

起点为1,终点为114

这张图正好有n+1条从1到114的路径,并且在这些路径的边权和中,[0,n]的每一个整数正好出现了一次。

问:给出一种可能的建图方法

----约束:边数<=45,点数<=18(包含1和114)


思路:

一. 考场做法:考虑将(n+1)分解质因数,(n+1)可能为素数或合数

1.若为素数:先将第n+1条边建起,然后考虑将(n)进行质因数分解
2.若为合数:则直接进行质因数分解

隐患:若分解后的质因数数集中有大于45的素数,则不符合题意

二. 转换方法:

n的范围是[1,32500],将32500进行二进制分解,位数不超过15位。

举例说明:

13(10) == 1101(2)

如图建边:(思路与数位dp相似)

[1]       [2]---0/4--->[3]---0/2--->[4]---0/1--->[114]
 |         ^            ^                          ^
 |----0--->|            |                          |
 |                      |                          |
 |---------8----------->|                          |
 |                                                 |
 |---------------------12/13---------------------->|

代码:

#include <bits/stdc++.h>
using namespace std;
int n,wei,cnt;

vector<pair<int,int> > ed[20];

void init() {
	int nn=n;
	while(nn) {
		wei++;
		nn>>=1;
	}
}

int main() {
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	cin>>n;
	init();
	for(int i=2;i<=wei-1;i++) {
		ed[i].push_back({i+1,0});
		ed[i].push_back({i+1,(1<<(wei-i))});
		cnt+=2;
	}
	ed[wei].push_back({114,0});
	ed[wei].push_back({114,1});
	cnt+=2;
	int nn=n;
	for(int i=0;i<wei;i++) {
		if(!((nn>>i)&1)) continue;
		int val=n-(((1<<(i+1))-1)&n);
		if(!i) ed[1].push_back({114,val});
		else ed[1].push_back({wei-i+1,val});
		cnt++;
	}
	ed[1].push_back({114,n});
	cnt++;
	cout<<wei+1<<' '<<cnt<<'\n';
	for(int i=1;i<=wei;i++) {
		for(int j=0;j<(int)ed[i].size();j++) {
			cout<<i<<' '<<ed[i][j].first<<' '<<ed[i][j].second<<'\n';
		}
	}
	return 0;
}
posted on 2024-11-04 21:02  Ueesugi_sakura  阅读(2)  评论(0编辑  收藏  举报