Codeforces Round #290 (Div. 2) D
题目要求满足如下约束条件的元组(l1,l2,l3,…,li)(l_1,l_2,l_3,\dots,l_i)(l1,l2,l3,…,li):
l1x1+l2x2+l3x3+⋯+lixi=1l_1x_1+l_2x_2+l_3x_3+\dots+l_ix_i=1l1x1+l2x2+l3x3+⋯+lixi=1
使得函数F=∑i=1nciF=\sum_{i=1}^{n}c_iF=∑i=1nci最小化。
说人话就是找到若干个数,它们的gcd=1且代价最小。
根据裴蜀定理,对于不全为0的整数a,b,存在整数解x,y,满足ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)
进而方程ax+by=cax+by=cax+by=c有整数解当且仅当gcd(a,b)∣cgcd(a,b)|cgcd(a,b)∣c。
扩展:c1x1+c2x2+c3x3+..+cnxn=dc_1x_1+c_2x_2+c_3x_3+..+c_nx_n=dc1x1+c2x2+c3x3+..+cnxn=d有解当且仅当gcd(c1,c2,c3,…,cn)∣dgcd(c_1,c_2,c_3,\dots,c_n)|dgcd(c1,c2,c3,…,cn)∣d
而找n个数的gcd可以通过两两求解。例如gcd(a1,a2,a3)=gcd(gcd(a1,a2),a3)gcd(a_1,a_2,a_3)=gcd(gcd(a_1,a_2),a_3)gcd(a1,a2,a3)=gcd(gcd(a1,a2),a3)
本题可用动态规划的方法求解,用dp[x]保存当若干个数的gcd为x时的最小代价。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
const int max_n=305;
ll a[max_n];
ll b[max_n];
unordered_map<ll,ll> dp;
vector<ll> v;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int main(void)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
for(int i=0;i<n;i++)
scanf("%lld",&b[i]);
ll ans=a[0];
for(int i=1;i<n;i++)ans=gcd(ans,a[i]);
if(ans!=1){
printf("-1\n");
return 0;
}
dp[a[0]]=b[0];
v.push_back(a[0]);
for(int i=1;i<n;i++)
{
ll cnt=v.size();
if(!dp[a[i]]){
dp[a[i]]=b[i];
v.push_back(a[i]);
}
else dp[a[i]]=min(dp[a[i]],b[i]);
for(int j=0;j<cnt;j++)
{
ll t=gcd(v[j],a[i]);
if(!dp[t]){
dp[t]=dp[v[j]]+b[i];
v.push_back(t);
}
else dp[t]=min(dp[t],dp[v[j]]+b[i]);
}
}
printf("%lld\n",dp[1]);
}