[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GiKCKoVM-1607157569836)(C:\Users\Stuedent\AppData\Roaming\Typora\typora-user-images\image-20201031190305068.png)]
根据某个(裴蜀)定理,有以下结论:
a x + b y = g c d ( a , b ) , 存 在 一 组 x , y 使 该 式 成 立 ax+by=gcd(a,b),存在一组x,y使该式成立 ax+by=gcd(a,b),存在一组x,y使该式成立
显然,当 g c d ( a , b ) = X gcd(a,b)=X gcd(a,b)=X的时候,能够跳到所有倍数是 X X X的格子。
因此,当 g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1的时候,我们能够跳到所有的格子。
这个可以推广到 n n n个数。
于是,题目便转化成从 n n n个数中选取若 k k k个数,使得 g c d ( l 1 , l 2 … … , l k ) = 1 gcd(l_1,l_2……,l_k)=1 gcd(l1,l2……,lk)=1,并且 ∑ i = 1 k c i \sum_{i=1}^k c_i ∑i=1kci最小
我们又 g c d = 1 gcd=1 gcd=1这一个强力的限制条件,因此我们可以做一遍 g c d gcd gcddp(背包)
设 f [ i ] f[i] f[i]表示 g c d gcd gcd为 i i i时的最小代价。答案显然就是 f [ 1 ] f[1] f[1]
考虑转移。枚举每一个数的时候,将 l [ i ] l[i] l[i]与之前所有出现过得 g c d ( j ) gcd(j) gcd(j)一一求一遍 g c d ( X ) gcd(X) gcd(X),于是就用 f [ j ] + c [ i ] f[j]+c[i] f[j]+c[i]来更新 f [ t m p ] f[tmp] f[tmp]
补充一个 M a p Map Map小知识。
如果你想访问 M a p Map Map,可以用迭代器来访问。
定义如下:
map < int , int > :: iterator it;
遍历的话用一下形势:
it = M.begin()
for (; it!=M.end(); ++it)
it->first//M的定义域
it->second//映射对应的值
由于本题的值域较大,数组无法存储,因此要用map代替数组进行dp
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10;
int n;
int l[N],c[N];
map < int , int > M;
int Min = 1e15+7;
int gcd(int x,int y){return y == 0?x:gcd(y,x%y);}
signed main(){
scanf("%lld",&n);
for (int i = 1; i <= n; i++) scanf("%lld",&l[i]);
for (int i = 1; i <= n; i++) scanf("%lld",&c[i]);
M[0] = 0;
for (int i = 1; i <= n; i++){
int Gc;
map < int , int > :: iterator it = M.begin();
for (;it != M.end(); ++it){
Gc = gcd(l[i],it->first);
if (M[Gc] == 0) M[Gc] = it->second+c[i];
else M[Gc] = min(M[Gc],it->second+c[i]);
if (Gc == 1) Min = min(Min,M[Gc]);
}
}
// if (M.count(1)) cout<<1;else cout<<0;
if (Min == 1e15+7) printf("-1");else printf("%lld",Min);
}