裴蜀定理:
定义:
若 \(a,b\) 不全为零,则存在 \(x,y\) ,使得 \(ax+by=gcd(a,b)\)
证明:
记住就行了,证明太长了不想写了.....
例题:
题意:
给出 \(n\) 张卡片,分别有 \(l_i\) 和 \(c_i\)。在一条无限长的纸带上,你可以选择花 c_i 的钱来购买卡片 \(i\) ,从此以后可以向左或向右跳 \(l_i\) 个单位。问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出 \(-1\)。
分析:
先考虑两个数情况:想要跳到每一个格子上,必须使得这些数通过数次相加/减得出的绝对值为 \(1\) ,进而想到了裴蜀定理。
推出:如果 \(a\) 与 \(b\) 互质,那么一定存在两个整数 \(x,y\) ,使得 \(ax+by=1\)。
若选择的卡牌通过数次相加或相减得出的绝对值为 \(1\) ,那么这些数一定互质.
因此问题转化成:选择若干个数使得 \(gcd\) 是 \(1\) 的最小代价。
考虑类似于背包的动态规划:设 \(gcd=x\) 的最小代价为 \(f_x\), 则式子为:
\[x=2,3,4,....,l_i,f_{gcd(x,l_i)}=min(f_{gcd(x,l_i)},f_x+c_i) \]
但是时间复杂度不行。
我们考虑消去无用状态:用 \(map\) 记录,每次访问过的 \(x\) 进行转移,差不多能过。
然后直接写就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
map<int,int> mp;
int a[1005],b[1005];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++){
for(pair<int,int> x:mp){
int num=__gcd(a[i],x.first);
int val=x.second+b[i];
if(mp[num]==0) mp[num]=val;
else mp[num]=min(mp[num],val);
}
if(mp[a[i]]==0) mp[a[i]]=b[i];
else mp[a[i]]=min(mp[a[i]],b[i]);
}
if(mp[1]==0) puts("-1");
else printf("%d\n",mp[1]);
system("pause");
return 0;
}