裴蜀定理
设 a,b是不全为零的整数,则存在整数 x,y, 使得 a*x+b*y=gcd(a,b) .
证明过程略
应用
给出 n张卡片,分别有li和ci。在一条无限长的纸带上,你可以选择花ci 的钱来购买卡片i,从此以后可以向左或向右跳li个单位。问你至少花多少元钱才能够跳到纸带上全部位置。若不行,输出-1。
解析:
分析该问题,先考虑两个数的情况,发现想要跳到每一个格子上,必须使得这些数通过数次相加或相加得出的绝对值为1 ,进而想到了裴蜀定理。
可以推出:如果a与b互质,那么一定存在两个整数x与y,使得ax+by=1 .
由此得出了若选择的卡牌的数通过数次相加或相减得出的绝对值为1,那么这些数一定互质,此时可以考虑动态规划求解。
不过可以转移思想,因为这些数互质,即为0号节点开始,每走一步求 gcd(节点号,下一个节点),同时记录代价,就成为了从0 通过不断gcd最后变为1的最小代价。
由于:互质即为最大公因数为1,gcd(0,x)=x 这两个定理,可以证明该算法的正确。选择优先队列优化 Dijkstra 求解。
不过还有个问题,即为需要记录是否已经买过一个卡片,开数组标记由于数据范围达到 10^9会超出内存限制,可以想到使用 unordered_map
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #include<queue> #include<string> #include<iostream> #include<stack> #define ll long long #define inf 0x3f3f3f3f template <class T> inline void gmax(T &a,T b){if(b>a)a=b;} template <class T> inline void gmin(T &a,T b){if(b<a)a=b;} using namespace std; const int N=303,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143; const double eps=1e-8,PI=acos(-1.0);//.0 map<int,int>mop; map<int,int>::iterator it; int l[N],c[N]; int n; int gcd(int x,int y) { int z; while(y) { z=x%y; x=y; y=z; } return x; } int main() { while(~scanf("%d",&n)) { mop.clear(); for(int i=1;i<=n;i++)scanf("%d",&l[i]); for(int i=1;i<=n;i++)scanf("%d",&c[i]); for(int i=1;i<=n;i++) { for(it=mop.begin();it!=mop.end();it++) { int x=it->first; int y=it->second; int g=gcd(l[i],x); if(mop.find(g)==mop.end())mop[g]=y+c[i]; else gmin(mop[g],y+c[i]); } if(mop.find(l[i])==mop.end())mop[l[i]]=c[i]; else gmin(mop[l[i]],c[i]); } if(mop.find(1)==mop.end())printf("-1 "); else printf("%d ",mop[1]); } return 0; }