@codeforces - [email protected] Koala and Notebook

目录

  • @[email protected]
  • @[email protected]
  • @accepted [email protected]
  • @[email protected]

@[email protected]

给定一个 n 点 m 边的无向连通图,每条边的编号按照输入顺序依次为 1, 2, ..., m。
现从 1 号点出发,当经过编号为 i 的边时,将 i 写下来。因为写的数之间没有空隙,所以写下来的所有数最终会连成一个数。
对于每一个除 1 以外的点,当它作为终点时,最终连成的数最小是多少?
输出答案模 10^9 + 7。注意,你应该输出 最小可能的数的余数,而不应该是 最小可能的余数

Input
第一行包含两个整数 n 和 m (2≤n≤10^5,n?1≤m≤10^5),表示点数与边数。
接下来 m 行,每行两个整数 xi 与 yi,表示第 i 条无向边连接 xi, yi。
保证没有重边。保证图连通。

Output
输出 n - 1 个数字,第 i 个数字表示以 i + 1 为终点的最小可能的数 mod 10^9 + 7。

Examples
Input
11 10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
Output
1
12
123
1234
12345
123456
1234567
12345678
123456789
345678826

@[email protected]

首先考虑一条边 u -> v 的权值如果为多位数 i,它的十进制表达为 \((d1...dm)_10\),则可以拆成 m 条边 u -> a1(d1), a1 -> a2(d2), ..., am-1 -> v(dm)。
这样就可以把每条边的权值都变为 0~9,方便我们下面的操作。

两个十进制数的比较,先比较位数,位数相同再比较字典序。
而在我们拆边后的图中,一条路径的距离就表示了这条路径代表的数的位数。
我们可以从点 1 出发跑最短路(其实跑 bfs 就好了),构建最短路图,则顺着最短路图走就可以保证位数最优。

接下来在最短路图上,我们考虑怎么才能走字典序最小的路径。
字典序是从前比到后,所以我们肯定是尽量保证先走权值最小的边。

但是有一个问题:假如权值最小的边有多个,应该选哪个?
正确的方法应该是同时增广这些边。将这些边连接的点连成链表形式,然后 dfs 的时候传表头即可。

@accepted [email protected]

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 2000000;
const int MOD = int(1E9) + 7;
struct edge{
    int to, key;
    edge(int _t=0, int _k=0):to(_t), key(_k) {}
};
vector<edge>G[MAXN + 5];
void addedge(int u, int v, int w) {
    G[u].push_back(edge(v, w));
//  printf("! %d %d %d\n", u, v, w);
}
int cnt;
void func(int u, int v, int id) {
    int p = id;
    while( p ) {
        if( p >= 10 )
            addedge(++cnt, u, p % 10), u = cnt;
        else addedge(v, u, p % 10);
        p /= 10;
    }
}
int d[MAXN + 5], n, m;
void bfs(int x) {
    queue<int>que;
    que.push(x); d[x] = 1;
    while( !que.empty() ) {
        int f = que.front(); que.pop();
        for(int i=0;i<G[f].size();i++) {
            edge p = G[f][i];
            if( !d[p.to] ) {
                d[p.to] = d[f] + 1;
                que.push(p.to);
            }
        }
    }
}
int ans[MAXN + 5], nxt[MAXN + 5];
bool vis[MAXN + 5];
void dfs(int x, int k) {
    int p = x;
    while( p ) ans[p] = k, p = nxt[p];
    for(int i=0;i<10;i++) {
        int q = -1, fir = -1; p = x;
        while( p ) {
            for(int j=0;j<G[p].size();j++) {
                edge &r = G[p][j];
                if( vis[r.to] || d[p] + 1 != d[r.to] )
                    continue;
                if( r.key == i ) {
                    if( q != -1 ) nxt[q] = r.to;
                    else fir = r.to;
                    vis[q = r.to] = true;
                }
            }
            p = nxt[p];
        }
        if( fir != -1 )
            dfs(fir, (10LL*k + i)%MOD);
    }
}
int main() {
    scanf("%d%d", &n, &m), cnt = n;
    for(int i=1;i<=m;i++) {
        int x, y; scanf("%d%d", &x, &y);
        func(x, y, i), func(y, x, i);
    }
    bfs(1), vis[1] = true, dfs(1, 0);
    for(int i=2;i<=n;i++)
        printf("%d\n", ans[i]);
}

@[email protected]

注意原图虽然是无向边,但是我们拆出来的边就变成了有向边。

枚举最小权值边,可以通过枚举 0~9(即枚举边权),找出对应权值的边。

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11521294.html

时间: 2024-11-08 17:10:59

@codeforces - [email protected] Koala and Notebook的相关文章

@codeforces - [email&#160;protected] Mashmokh&#39;s Designed Problem

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一棵 n 个点的树,每个点的儿子是有序的. 现给定 m 次操作,每次操作是下列三种中的一种: (1)给定 u, v,询问 u, v 之间的距离. (2)给定 v, h,断开 v 到父亲的边,将 v 这棵子树加入到它的第 h 个祖先的最后一个儿子. (3)给定 k,询问在当前这棵树上

@codeforces - [email&#160;protected] T-Shirts

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 有 n 件 T-shirt,第 i 件 T-shirt 有一个 ci 和 qi,分别表示费用与质量. 同时有 k 个顾客,第 j 个顾客准备了 bj 的金钱去购买 T-shirt. 每个顾客的购买策略是相同的: 他会买他的资金范围内 q 值最大的一件,如果有多个选 c 最小的一件,每种

@codeforces - [email&#160;protected] Oleg and chess

目录 @description - [email protected] @[email protected] @part - [email protected] @part - [email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @[email protected] @description - [email protected] 给定一个 n*n 的棋

@codeforces - [email&#160;protected] Lucky Tickets

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 已知一个数(允许前导零)有 n 位(n 为偶数),并知道组成这个数的数字集合(并不一定要把集合内的数用完).求有多少种可能,使得这个数前半部分的数位和等于后半部分的数位和. 模 998244353. input 第一行两个整数:n k.表示这个数的位数以及组成这个数的数字集合大小.2

@codeforces - [email&#160;protected] Bandit Blues

目录 @[email protected] @[email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @[email protected] @[email protected] 求有多少个长度为 n 的排列,从左往右遍历有 a 个数比之前遍历的所有数都大,从右往左遍历有 b 个数比之前遍历的所有数都大. 模 998244323. input 一行三个整数 n

@codeforces - [email&#160;protected] Vus the Cossack and a Field

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个 n*m 的 01 矩阵,通过这个矩阵生成一个无穷矩阵,具体操作如下: (1)将这个矩阵写在左上角. (2)将这个矩阵每位取反写在右上角. (3)将这个矩阵每位取反写在左下角. (4)将这个矩阵写在右下角. (5)将得到的矩阵再作为初始矩阵,重复这些操作. 比如对于初始矩阵:

@codeforces - [email&#160;protected] Big Problems for Organizers

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] n 个点连成一棵树,经过每条边需要花费 1 个单位时间. 现给出 m 次询问,每次询问给出两个点,需要求所有点同时出发,最终所有点到达这两个点之一的最小花费时间. input 第一行包含一个整数 n (2?≤?n?≤?100000) ,表示点数. 接下来 n-1 行每行两个 1~n 的

@codeforces - [email&#160;protected] Strongly Connected Tournament

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] n 个选手参加了一场竞赛,这场竞赛的规则如下: 1.一开始,所有选手两两之间独立进行比赛(没有平局). 2.主办方将胜者向败者连边形成 n 个点的竞赛图. 3.主办方对这个竞赛图进行强连通分量缩点. 4.每一个强连通分量内部的选手重复步骤 1~3,直到每一个强连通分量内只剩一个选手.

@codeforces - [email&#160;protected] Rotate Columns (hard version)

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个 n*m 的矩阵 A. 定义一次操作为将矩阵的某一列竖着循环移位,你可以对任意列做任意次操作. 定义 ri 为第 i 行的最大值,最大化 r1 + r2 + ... + rn. Input 第一行一个整数 t (1≤t≤40),表示数据组数. 每组数据第一行包含两个整数 n m