• AtCoder "Regular Contest 102" D



    Regular Contest 102 - D - All Your Paths are Different Lengths


    题意

    给定一个(L),要求构造出一个点数(n)不超过(20),边数(m)不超过(60)的有向图(允许存在重边)

    保证该图从点(1)到点(n)存在恰好(L)不同的路径,每条路径权值和互异,且在([0,L-1])之间


    限制

    (2leq Lleq 10^6)




    思路

    第一部分

    考虑([0,L-1])内数字的二进制表示法

    由于每个数字都能表示成多个(2)的次方幂之和,换句话说,为了表示出某个数字,对于每个(2)的次方幂可以决定是选还是不选(二进制上(1)表示选择,(0)表示不选)

    以有向图进行表示,则可以按顺序连接两条(i)(i+1)的边,一条权值为(2^{i-1})表示选择,一条权值为(0)表示不选择

    得到的有向图如下图所示:

    p1

    上图从第(1)个点走到第(7)个点,所能表示的数值范围为([0,111111B=63])

    第二部分

    但发现题目限制(nleq 20),因此最多只能够表示到(2^{18}=262144)过,此时整张图(20)个点所能表示的数字范围为([0,2^{19}-1=524287]),无法满足(L=1000000)的情况

    前面提及:

    • 如果只考虑第(1)个点到第(i)个点,其所能表示出的数字范围为([0,2^{i-1}-1])

    而如果给这个范围加上一个常数(a),就变得能够表示([a,a+2^{i-1}-1])内的数字了

    假设此前我们所能表示出的数字为([0,limit-1]),以(limit)变量表示此时最小的不能表示出的数字

    (limit)变量作为常数,那就可以将([limit,limit+2^{i-1}-1])之内的数字表示出来了

    换在构造的有向图中,这也就表示自第(i)个点向第(n)个点连一条权值为(limit)的边

    建边后,(limit)也就变成了(limit+2^{i-1})

    下图表示(L=74)(边权和范围为([0,73]))所构造出的有向图:

    p2

    第三部分

    上述方法实际上也就是考虑(L-limit)的二进制表示法上(1)所在的位置,并将其与终点连边

    所以需要让(i)从大到小遍历去判断是否第(1)个位置到第(i)个位置所能表示的数字数量((2^{i-1}))小于剩余的不能表示出的数字数量((L-limit))

    因此,本题只需要循环遍历两遍即可,具体实现方式详见代码部分

    本思路点数(n)最多为(20),边数最多为((20-1)*2+19leq 60),满足题意




    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    struct node
    {
        int u,v,w;
        node(){}
        node(int u,int v,int w):u(u),v(v),w(w){}
    };
    vector<node> ans;
    int L,mx,sum[25];
    
    int main()
    {
        scanf("%d",&L);
        L--;
        
        sum[1]=0;
        for(int i=1;i<=20;i++)
        {
            sum[i+1]=sum[i]+(1<<(i-1)); //到第i+1个点所能表示出的最大数字
            if(sum[i+1]<=L) //如果在L-1的范围内
            {
                ans.push_back(node(i,i+1,1<<(i-1))); //两点间进行2的次方幂连边
                ans.push_back(node(i,i+1,0)); //不选
                mx=i+1;
            }
            else
                break;
        }
        
        int limit=sum[mx]+1; //limit用于表示此时最小的不能表示出的数字
        for(int i=mx;i;i--)
        {
            if(sum[i]<=L-limit) //如果连一条limit的边,不会超出范围
            {
                ans.push_back(node(i,mx,limit));
                limit+=sum[i]+1; //注意+1
            }
        }
        
        printf("%d %d
    ",mx,ans.size());
        for(node &nd:ans)
            printf("%d %d %d
    ",nd.u,nd.v,nd.w);
        
        return 0;
    }
    

  • 相关阅读:
    arguments.callee
    vue的生命周期
    Vue中的v-cloak用法
    控制input只能输入数字和两位小数
    css3新单位vw、vh的使用详解
    关于图片的Base64编码
    Logic and Fault simulation
    scan design flow(二)
    scan design flow(一)
    异构计算
  • 原文地址:https://www.cnblogs.com/stelayuri/p/13782433.html
Copyright © 2020-2023  润新知