510D Fox And Jumping(dp+gcd)

来源:互联网 发布:南风知我意txt百度云 编辑:程序博客网 时间:2024/05/22 06:38

有一条无限长的条带,上面有带编号的格子,由负到正。(相当于一条数轴)

现有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;}


0 0