zoukankan      html  css  js  c++  java
  • 【CF1479C】Continuous City(构造)

    点此看题面

    • 给定(L,R),你可以用至多(32)个点构造一张简单(DAG),并给每条边定一个正边权。
    • 要求使得(1 ightarrow n)所有路径长度构成的集合恰好是([L,R])
    • (1le Lle Rle10^6)

    二进制分解

    这种题目应该很容易往二进制分解的方向去想。

    首先说明,无论(L,R)取何值,答案都一定是(YES),且按照我的方法应该只要让(n=22)就可以了。

    考虑我们先从(1)号点向所有点连一条长度为(L)的边,现在问题就在于如何构造出值域为([1,R-L])的路径长度。

    对于所有(iin[2,20]),从(i)号点向之后除(n)号点以外所有点连一条长度(2^{i-2})的边。

    容易发现,此时(1 ightarrow i)的路径长度值域其实是([L,L+2^{i-2}-1])

    接下来就是要考虑怎么用它们来凑出(R-L),实际上我们可以直接让(23)号点成为(n)号点。

    我们枚举(iin[2,21]),如果(R-L)(i-2)位是(1),则令(t)表示将(R-L)(i-2)位都修改为(0)后的值,然后我们就从(i)(n)号点连一条权值为(t+1)的边。这样一来(1 ightarrow n)路径长度的值域就添上了([L+t+1,L+t+2^{i-2}])

    具体的理解最好还是自己画个图比较好。

    代码:(O(20^2))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 32
    #define Add(x,y,z) (tot+=sprintf(s+tot,"%d %d %d
    ",x,y,z),++cnt)//存下一条边的输出,因为要先输出边数
    using namespace std;
    int L,R,cnt,tot;char s[10000000];
    int main()
    {
    	RI i,j,t;scanf("%d%d",&L,&R),puts("YES"),Add(1,22,L);//从1号点向n号点连边
    	for(i=1;i<=20;++i) for(t=i^1?1<<i-2:L,j=i+1;j<=21;++j) Add(i,j,t);//从1~20号点向之后除n号点以外的点连边
    	for(t=R-L,i=2;i<=21;++i) t>>(i-2)&1&&(t^=1<<i-2,Add(i,22,t+1));//将R-L二进制分解
    	End:return printf("22 %d
    ",cnt),puts(s),0;//输出构造方案
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    详解 final 和 static
    详解 方法的覆盖 —— toString() 与 equals()的覆盖
    详解 继承(上)—— 工具的抽象与分层
    详解 继承(下)—— super关键字 与 多态
    Java 基础讲解
    矩阵 的实现
    C语言 贪吃蛇
    巨大数——三则运算(+、-、*)
    浅谈 循环数组
    人体对电流的反应
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF1479C.html
Copyright © 2011-2022 走看看