有一条无限长的条带,上面有带编号的格子,由负到正。(相当于一条数轴)
现有n张卡片,上面记载着长度和花费。获取第i张卡片需要花费c[i],然后可以跳l[i]个距离到x+l[i]或者x-l[i]的位置(购买卡片后可重复使用),初始在0这个位置。问最少要花费多少可以跳到条带的任意位置。
要跳到任意位置,只需购买的所有卡片的长度的最大公约数为1。
设两数为x,y,其最大公约数为m。a、b为任意整数。
则a*x+b*y=m*(a*x/m+b*y/m),其能够表示所有为m的倍数的整数
要使得其能够表示1,则m必为1
设dp[i]表示最大公约数为i时的最小花费。求出各个可能出现的最大公约数维护其值即可。最后若dp中存在1,则有解,否则无解。
#include<bits/stdc++.h>
using namespace std;
int l[302],c[302];
vector<int> num;
map<int,int>dp;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int n,i,j;
scanf("%d",&n);
for(i=1;i<=n;++i) scanf("%d",&l[i]);
for(j=1;j<=n;++j) scanf("%d",&c[j]);
for(i=1;i<=n;++i)
{
if(dp.count(l[i]))dp[l[i]]=min(dp[l[i]],c[i]);
else
{
dp[l[i]]=c[i];
num.push_back(l[i]);
}
}
for(i=1;i<=n;++i)
for(j=0;j<num.size();++j)
{
int temp=gcd(l[i],num[j]);
if(dp.count(temp)) dp[temp]=min(dp[temp],dp[l[i]]+dp[num[j]]);
else
{
dp[temp]=dp[l[i]]+dp[num[j]];
num.push_back(temp);
}
}
if(dp.count(1)) printf("%d\n",dp[1]);
else puts("-1");
return 0;
}