【hdu 3579】Hello Kiki(数论--拓展欧几里德 求解同余方程组)

题意:Kiki 有 X 个硬币,已知 N 组这样的信息:X%x=Ai , X/x=Mi (x未知)。问满足这些条件的最小的硬币数,也就是最小的正整数 X。

解法:转化一下题意就是 拓展欧几里德求解同余方程组了。我们可以得到 N 个方程:Mi*x+Ai=X。一些解释请看下面的代码。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 LL aa[8],mm[8];
 9 
10 LL mabs(LL x) {return x>0?x:-x;}
11 LL exgcd(LL a,LL b,LL& x,LL& y)
12 {
13     if (!b) {x=1,y=0; return a;}
14     LL d,tx,ty;
15     d=exgcd(b,a%b,tx,ty);
16     x=ty,y=tx-(a/b)*ty;
17     return d;
18 }
19 int main()
20 {
21     int T,n;
22     scanf("%d",&T);
23     for (int kase=1;kase<=T;kase++)
24     {
25       scanf("%d",&n);
26       for (int i=1;i<=n;i++) scanf("%I64d",&mm[i]);
27       for (int i=1;i<=n;i++) scanf("%I64d",&aa[i]);
28       LL a,m,d,x,y;
29       a=aa[1],m=mm[1];
30       bool ok=false;
31       for (int i=2;i<=n;i++)
32       {
33         d=exgcd(m,mm[i],x,y);//mx-mm[i]y=aa[i]-a
34         if ((aa[i]-a)%d!=0) {ok=true;break;}
35         x=x*((aa[i]-a)/d);
36         LL t=mabs(mm[i]/d);
37         x=(x%t+t)%t;
38         a=m*x+a,m=m*mm[i]/d;//保证了x最小,a相应的也是最小的
39       }
40       LL ans;
41       if (ok) ans=-1;
42       else {ans=a; if (!ans) ans+=m;}
43       printf("Case %d: %I64d\n",kase,ans);
44     }
45     return 0;
46 }

 

posted @ 2016-11-15 08:38  konjac蒟蒻  阅读(157)  评论(0编辑  收藏  举报