【Atcoder - ARC102D/ABC108D】All Your Paths are Different Lengths

版权声明:本文为博主原创文章……懂吗?要尊重别人的劳动成果呐 https://blog.csdn.net/Tiw_Air_Op1721/article/details/82346293

@All Your Paths are Different Lengths@


@题目描述 - English@

Time limit : 2sec / Memory limit : 1024MB

Score : 700 points

Problem Statement
You are given an integer L. Construct a directed graph that satisfies the conditions below. The graph may contain multiple edges between the same pair of vertices. It can be proved that such a graph always exists.

The number of vertices, N, is at most 20. The vertices are given ID numbers from 1 to N.
The number of edges, M, is at most 60. Each edge has an integer length between 0 and 10^6 (inclusive).
Every edge is directed from the vertex with the smaller ID to the vertex with the larger ID. That is, 1,2,…,N is one possible topological order of the vertices.

There are exactly L different paths from Vertex 1 to Vertex N. The lengths of these paths are all different, and they are integers between 0 and L−1.
Here, the length of a path is the sum of the lengths of the edges contained in that path, and two paths are considered different when the sets of the edges contained in those paths are different.

Constraints
2≤L≤10^6
L is an integer.

Input
Input is given from Standard Input in the following format:
L

Output
In the first line, print N and M, the number of the vertices and edges in your graph. In the i-th of the following M lines, print three integers ui,vi and wi, representing the starting vertex, the ending vertex and the length of the i-th edge. If there are multiple solutions, any of them will be accepted.

Sample Input 1
4
Sample Output 1
8 10
1 2 0
2 3 0
3 4 0
1 5 0
2 6 0
3 7 0
4 8 0
5 6 1
6 7 1
7 8 1

In the graph represented by the sample output, there are four paths from Vertex 1 to N=8:
1 → 2 → 3 → 4 → 8 with length 0
1 → 2 → 3 → 7 → 8 with length 1
1 → 2 → 6 → 7 → 8 with length 2
1 → 5 → 6 → 7 → 8 with length 3
There are other possible solutions.

Sample Input 2
5
Sample Output 2
5 7
1 2 0
2 3 1
3 4 0
4 5 0
2 4 0
1 3 3
3 5 1

@大致题意@

构造一个 n 点 m 边的有向带权图,要求边必须从节点编号小的连向结点编号大的。允许重边。要使得从结点 1 到结点 n 恰好有 L 条路径,这 L 条路径的长度互不相同且在[0,L-1]范围内。
n<=20, m<=60, L<=10^6

@分析1@

【蛮有趣的构造题】
首先观察数据范围,发现2^20 = 1048576 ≈ 1000000 = 10^6……
你要说这是巧合我绝对不信。
然后,注意到题目特别提到了“重边”。
然后,“用几个数之和表示[0,L-1]的所有数”,如果单看这个没什么思路,但如果结合上面数据范围的话……
二进制表达。
两个点之间连两条边,权值分别为0与2^i。
大致的构造思路就差不多是这样,详细细节在下面。

@分析2@

我们不妨总是令n=20。
对于2<=i<=19的结点,我们i与i+1之间连两条边,一条权值为 0 ,一条权值为 2 20 i 1
这样,如果1号结点向i号结点连一条权值为w的边,那么从1到20就会出现 w + [ 0...2 20 i 1 ] 的所有数。

接下来?我们不妨采用数位dp的思想。

假设将L转化成二进制形式,即令 L = i = 0 2 i b [ i ] L 。一个小于L的数x应该具有什么特征呢?如果存在一个p,使得:
1 i = p + 1 2 i b [ i ] L = i = p + 1 2 i b [ i ] x (前面所有数位相同)
2 b [ p ] L > b [ p ] x (当前数位L>x)
两个条件成立,则x < L。这个时候我们发现如果(2)成立,则 b [ p ] L = 1

所有小于L的数应该是如下形式的集合并:
i = p + 1 2 i b [ i ] L + 0 + [ 0...2 p 1 ] ( b [ p ] L = 1 ) (前面所有数位相同,当前数位为0,后面的数位随便选)

构造方法就出来了:如果 b [ p ] L = 1 ,则由1向(20-p)连一条边权为 i = p + 1 2 i b [ i ] L 的边。

但是我们发现如果完全按照上面的思路构造,当p=19时,我们将会1向1连边……
所以我们必须特判 p = 19 的情况。对于这种情况,我们将1与2之间连两条边,边权为 0 2 18

@代码@

【实现上为了简单,我用了lowbit枚举L的每一个含有1的位】
如果还有什么问题可以参考代码或者是留言给我~我会尽力解答的~

#include<cmath>
#include<cstdio>
#include<vector>
using namespace std;
struct node{
    int u, v, w;
    node(int _u, int _v, int _w):u(_u), v(_v), w(_w){}
};
vector<node>ans;
inline int lowbit(int x) {
    return x & -x;
}
int main() {
    int L;
    scanf("%d", &L);
    for(int i=19;i>1;i--) {
        ans.push_back(node(i, i+1, 0));
        ans.push_back(node(i, i+1, (1<<(20-i-1))));
    }
    while( L ) {
        int p = int(log2(lowbit(L)));
        if( p == 19 ) {
            ans.push_back(node(1, 2, 0));
            ans.push_back(node(1, 2, 1<<18));
        }
        else ans.push_back(node(1, 20-p, L^lowbit(L)));
        L ^= lowbit(L);
    }
    printf("%d %d\n", 20, ans.size());
    for(int i=0;i<ans.size();i++)
        printf("%d %d %d\n", ans[i].u, ans[i].v, ans[i].w);
} 

@END@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

猜你喜欢

转载自blog.csdn.net/Tiw_Air_Op1721/article/details/82346293
今日推荐