裴蜀定理:
定義:
若 \(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;
}
