问:
花费代价买一个卡片,就可以任意加减这个卡片的数值,最少花多少钱可以表示所有数。
思考:
考虑所有数即可以表示1,因为 裴蜀定理
ax + by = gcd(a, b)有整数解
当x,y互质的时候就可以表示出来1了
所以我们要通过不断买卡片,缩小这些数的最小公因数直到1
做法1:
暴力DFS 用mp维护获得当前最小公约数的值,来剪枝。可以再加个启发式搜索,不过还是T了。
DFS有太多重复的情况,每个卡片会多次被选择,每个卡片其实最多选一次就够了。因为这些数字数量很少,公约数也是很少的,考虑维护一个公约数的序列,可以开个优先队列,也可以直接在map上遍历(不能用哈希map,因为是无序的,边插入边跑可能漏数)。
做法2:
考虑每个卡片最多选一次,维护的是一个公约数,利用map的有序性,为了保证每个数只使用一次,最外层遍历n个数,每个数和map里面的所有元素进行更新。 复杂度 n * m * log(m) m为最大公约数个数。
注意:
map 和 unordered_map 虽然unordered_map是哈希 O(n)就能访问,但是是无序的,边更新边遍历会漏数。
map遍历用 迭代器p p.first p.second
#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize (2)
//#pragma GCC optimize (3)
#pragma GCC optimize (Ofast)
#define fastio ios_base::sync_with_stdio(0); cin.tie(NULL);
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i--)
#define LL long long
#define endl "\n"
#define debug1 cout << "???" << endl;
#define debug2(x) cout << #x << ": " << x << endl;
const int INF = 0x3f3f3f3f;
const int N = 3e2+7;
int n;
LL minn, a[N], c[N];
map <LL, LL> mp;
LL GCD(LL a, LL b)
{
return b == 0 ? a : GCD(b, a%b);
}
int main()
{
fastio
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
cin >> n;
rep(i, 1, n)
cin >> a[i];
rep(i, 1, n)
cin >> c[i];
rep(i, 1, n)
{
if(!mp[a[i]])
mp[a[i]] = c[i];
else
mp[a[i]] = min(mp[a[i]], c[i]);
for(auto p : mp)
{
LL gcd = GCD(a[i], p.first);
if(!mp[gcd])
mp[gcd] = c[i] + p.second;
else
mp[gcd] = min(mp[gcd], c[i] + p.second);
}
}
if(!mp[1])
cout << "-1\n";
else
cout << mp[1] << endl;
return 0;
}