Wannafly 挑战赛12 E

链接:https://www.nowcoder.com/acm/contest/79/E
来源:牛客网

题目描述

小欧在上代数课的时候,老师向大家提出了一个问题,不定方程 ax+by=c 的整数解存在的充要条件是什么。
聪明的小欧立即举手给出了老师一个完美的回答,放学后,老师叫住小欧给了他一个思考题。
给出正整数 a 和 b 的值以及两个序列 S 和 V, 求出最小代价的正整数 c 使得不定方程 ax+by=c 有解,且 c 必须满足以下条件:
1. 组成 c 的数字必须是序列 S 内的。
2. 每使用序列 S 内的一个数字 S i 就会消耗掉代价 V i
3. 序列 S 内的数字使用次数不限。
4. c 的首位为 u, c的末位为 v。(u,v 也是序列 S 内的) 
如果有多个代价一样小的答案,只需要 c 的字典序最小的那一个。

输入描述:

第一行三个个整数 a,b,n (1 <= a, b <= 100000,  2 <= n <= 10) 
第二行 n 个整数 S
i
(0 <= S
i
 <= 9) 
第三行 n 个整数 V
i
(1 <= V
i
<= 1000) 
最后一行两个整数 u,v(1 <= u <= 9,  0 <= v <= 9, u != v) 

输出描述:

输出一行表示满足条件的 c 。
如果有多个输出字典序最小的。
如果不存在输出 -1 。
示例1

输入

10 15 2
2 0
1 1
2 0

输出

20
示例2

输入

17 17 4
0 1 2 7
1 1 1 1000
1 0

输出

1020

思路:对于0到1e5的每一个值建一个节点,每个数字对应一条边,u到v有一条数字为x的边当且仅当(u * 10 + x) % gcd(a, b) == v。想到这里,建图完毕直接跑个dij就行了。但是有一个问题,要输出字典序最小路径,正向可能不好记录,
可以反向建图跑最短路。反向图的起点值是0,连接所有 满足(w * 10 + v) % 10 == 0的w节点即可,但这个0与路径上普通的节点0是不同的,我们要将这个点特殊化一下,可以赋成一个独特的下标10001。最后求10001到u的最短路即可,更新路径
时根据决策记录上一个节点以及到达此节点的边。
  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include <string>
  8 #include 
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include <set>
 14 #include 
 15 #include 
 16 #include 
 17 #include 
 18 #include 
 19 #include 
 20 #include 
 21 
 22 using namespace std;
 23 
 24 #define pau system("pause")
 25 #define ll long long
 26 #define pli pair
 27 #define pii pair
 28 #define pb push_back
 29 #define mp make_pair
 30 #define clr(a, x) memset(a, x, sizeof(a))
 31 
 32 const double pi = acos(-1.0);
 33 const int INF = 0x3f3f3f3f;
 34 const int MOD = 1e9 + 7;
 35 const double EPS = 1e-9;
 36 
 37 /*
 38 #include 
 39 #include 
 40 
 41 using namespace __gnu_pbds;
 42 tree, rb_tree_tag, tree_order_statistics_node_update> T;
 43 */
 44 
 45 int a, b, n, s[15], val[15], u, v, g, cost[15];
 46 int dis[100015];
 47 pii pre[100015];
 48 struct edge {
 49     int v, x;
 50     edge () {}
 51     edge (int v, int x) : v(v), x(x) {}
 52 };
 53 vector E[100015];
 54 
 55 int gcd(int a, int b) {
 56     return b ? gcd(b, a % b) : a;
 57 }
 58 
 59 void build_graph() {
 60     for (int i = 0; i <= 100000; ++i) {
 61         for (int j = 0; j < 10; ++j) {
 62             if (INF != cost[j]) {
 63                 //E[i].pb(mp((i * 10 + j) % g, cost[j]));
 64                 if ((i * 10 + j) % g == i) continue;
 65                 E[(i * 10 + j) % g].pb(edge(i, j));
 66             }
 67         }
 68     }
 69     for (int i = 0; i <= 100000; ++i) {
 70         if (0 == (i * 10 + v) % g) {
 71             E[100001].pb(edge(i, v));
 72         }
 73     }
 74 }
 75 
 76 int dij() {
 77     clr(dis, INF);
 78     for (int i = 0; i < 100010; ++i) {
 79         pre[i].first = INF;
 80         pre[i].second = INF;
 81     }
 82     priority_queue, greater > que;
 83     int s = 100001;
 84     que.push(pli(dis[s] = 0, s));
 85     while (que.size()) {
 86         pli p = que.top(); que.pop();
 87         ll d = p.first;
 88         int x = p.second;
 89         if (dis[x] < d) continue;
 90         for (int i = 0; i < E[x].size(); ++i) {
 91             int y = E[x][i].v, v = E[x][i].x;
 92             /*if (x == y) {
 93                 printf("x = y = %d\n", x);
 94                 pau;
 95             }*/
 96             int td = d + cost[v];
 97             if (dis[y] < td) continue;
 98             if (td < dis[y]) {
 99                 que.push(pli(dis[y] = td, y));
100                 pre[y] = mp(x, v);
101             } else {
102                 if (v < pre[y].second) pre[y] = mp(x, v);
103             }
104         }
105     }
106     return dis[u];
107 }
108 
109 int main() {
110     scanf("%d%d%d", &a, &b, &n);
111     g = gcd(a, b);
112     clr(cost, INF);
113     for (int i = 1; i <= n; ++i) {
114         scanf("%d", &s[i]);
115     }
116     for (int i = 1; i <= n; ++i) {
117         scanf("%d", &val[i]);
118         cost[s[i]] = min(cost[s[i]], val[i]);
119     }
120     scanf("%d%d", &u, &v);
121     build_graph();
122     if (INF == dij()) {
123         puts("-1");
124     } else {
125         printf("%d", u);
126         int s = u;
127         while (100001 != s) {
128             printf("%d", pre[s].second);
129             s = pre[s].first;
130         }
131     }
132     return 0;
133 }
View Code

 

转载于:https://www.cnblogs.com/BIGTOM/p/8672318.html

你可能感兴趣的:(Wannafly 挑战赛12 E)