• AtCoder Regular Contest 102 (ARC102) D All Your Paths are Different Lengths 构造


    原文链接https://www.cnblogs.com/zhouzhendong/p/ARC102D.html

    题目传送门 - ARC102D

    题意

      给定 $L$,请你构造一个节点个数为 $n$ ,边数为 $m$ 的图,边带权,满足以下条件:

      1. $nleq 20$

      2. $mleq 60$

      3. 如果有向边 $a ightarrow b$ 存在,那么 $a<b$ 。

      4. 从 $1$ 走到 $n$ 总共有 $L$ 种不同的路径,这 $L$ 条路径的长度分别为 $0,1,cdots , L-1$ 。

      $Lleq 10^6$

    题解

      垃圾翻译告诉我 $ngeq 20$ 。于是我立马构造了一个 $40$ 个点的图来满足。在看样例的时候,我发现读错了题目。

      然后我就一直在想如何用 $2^k$ 的边权来构造。不知道为什么我只在想用这种边权构造。

      然后我扔掉这种做法想出了一个 AC 做法,5分钟敲完 AC 了。赛后,Funtionendless 给我讲了一下他口胡的做法,然而我发现和我之前想的假做法好像,说他是错的;然后最后我发现我…… 于是我又知道了一种做法。

      由于这两种做法的正确性都比较显然,所以不加解释。

      做法1:by me

    build(x,L){//以x为当前子图的最小标号节点,构造一个具有 [0,L] 的路径长度的图
    	if (L==0){
    		AddEdge(x,n,0);
    		return;
    	}
    	if (L==1){
    		AddEdge(x,n,0);
    		AddEdge(x,n,1);
    		return;
    	}
    	y=NewNode();
    	if (L mod 2==0)
    		AddEdge(x,n,L);
    	if (L mod 2==0)
    		L=L div 2-1;
    	else
    		L=L div 2;
    	AddEdge(x,y,0);
    	AddEdge(x,y,L);
    	build(y,L);
    }
    

      

      做法2:by Funtionendless

    int calc(int x,int i){//以x为当前子图的最小标号节点,构造一个具有 [0,L) 的路径长度的图
    	return x&~((1<<(i+1))-1);
    }
    int GetD(int x,int i){
    	return  x的i次二进制位;
    }
    n=20;
    build(x,L){
    	for (i = 0 to 18){
    		AddEdge(i+1,i+2,Pow(2,i));
    		AddEdge(i+1,i+2,0);
    	}
    	if (GetD(0))
    		AddEdge(1,n,calc(L,0));
    	for (i = 1 to 19)
    		if (GetD(L,i)==1)
    			AddEdge(i,n,calc(L,i));
    }
    

      

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=105;
    LL read(){
    	LL x=0,f=1;
    	char ch=getchar();
    	while (!isdigit(ch)&&ch!='-')
    		ch=getchar();
    	if (ch=='-')
    		f=-1,ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    	return x*f;
    }
    int n,m=0,L;
    int A[N],B[N],C[N];
    void push(int a,int b,int c){
    	m++;
    	A[m]=a;
    	B[m]=b;
    	C[m]=c;
    }
    int main(){
    	L=read()-1;
    	n=20;
    	int cnt=1;
    	while (L>=0){
    		if (L==0){
    			if (cnt<n)
    				push(cnt,n,0);
    			break;
    		}
    		if (L==1){
    			push(cnt,n,0);
    			push(cnt,n,1);
    			break;
    		}
    		if (L%2==0)
    			push(cnt,n,L);
    		L=(L+1)/2;
    		push(cnt,cnt+1,0);
    		push(cnt,cnt+1,L);
    		L--;
    		cnt++;
    	}
    	printf("%d %d
    ",n,m);
    	for (int i=1;i<=m;i++)
    		printf("%d %d %d
    ",A[i],B[i],C[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    STM8s窗口看门狗
    开篇
    习题6-8 统计一行文本的单词个数
    习题9-4 查找书籍
    习题9-3 平面向量加法
    习题9-1 时间换算
    习题7-8 字符串转换成十进制整数
    习题8-10 输出学生成绩
    习题7-7 字符串替换
    习题7-6 统计大写辅音字母
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/ARC102D.html
Copyright © 2020-2023  润新知