P r o b l e m \mathrm{Problem} Problem
给出 n n n 张卡片,分别有 l i l_i li? 和 c i c_i ci?。
在一条无限长的纸带上,你可以选择花 c i c_i ci? 的钱来购买卡片 i i i,从此以后可以向左或向右跳 l i l_i li? 个单位。
问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出 ? 1 -1 ?1。
S o l u t i o n \mathrm{Solution} Solution
若对于数字 a a a 和数字 b b b ,根据裴蜀定理,方程 a x + b y = c ( g c d ( a , b ) ∣ c ) ax+by=c(\mathrm{gcd}(a,b)|c) ax+by=c(gcd(a,b)∣c)恒有解。
因此若我们能拼出 x x x 的任何倍数,我们就可以用 c i c_i ci? 拼出 gcd ? ( x , l i ) \gcd (x,l_i) gcd(x,li?) 任何数。
这对应了一个最短路模型,我们以 0 0 0 跑最短路即可,主要要用map或哈希存储。
C o d e \mathrm{Code} Code
#include <bits/stdc++.h>
#define int long longusing namespace std;
const int N = 2e5;int n;
int c[N], l[N];
map < int, int > vis, dis;
priority_queue < pair<int, int> > q;int read(void)
{
int s = 0, w = 0; char c = getchar();while (!isdigit(c)) w |= c == '-', c = getchar();while (isdigit(c)) s = s*10+c-48, c = getchar();return w ? -s : s;
}int gcd(int a, int b) {
if (b == 0) return a;return gcd(b, a % b);
}int Dijkstra(void)
{
q.push({
dis[0] = 0LL, 0LL});while (q.size()){
int x = q.top().second; q.pop();if (vis[x]) continue; vis[x] = 1;if (x == 1) return dis[1];for (int i=1;i<=n;++i){
int y = gcd(l[i], x);if (dis.count(y) == 0) dis[y] = 1e18;if (dis[x] + c[i] < dis[y]) {
dis[y] = dis[x] + c[i];q.push({
-dis[y], y});} }}return -1;
}signed main(void)
{
n = read();for (int i=1;i<=n;++i) l[i] = read();for (int i=1;i<=n;++i) c[i] = read();cout << Dijkstra() << endl;return 0;
}