【poj 2115】C Looooops(數論--拓展歐幾里德 求解同余方程 模版題)


題意:有一個在k位無符號整數下的模型:for (variable = A; variable != B; variable += C)  statement; 問循環的次數,若“永不停息”(←_←)*,就輸出"FOREVER"。

解法:用拓展歐幾里德方法求出gcd最大公因數,再利用同余性質轉化,求同余方程,或者不定方程。其中題目可化為 a+cx=b(mod 2^k) → cx=b-a(mod 2^k),求最小正整數解。也是求解同余方程。

   先將方程化為一般形式:ax=c(mod p) →  ax+py=c 。若 gcd(a,p)|c,就可以利用 ax+py=gcd(a,b)(mod p) [一般沒有mod p] ,再把變量 x,y 乘上 c/gcd(a,b) 就是答案了。而要求最小正整數解,就是根據 ax+py=gcd(a,p) → a(x+p/gcd(a,p))+p(y-a/gcd(a,p)=gcd(a,p) ,所有的 x' 都滿足 x+p/gcd(a,p) 來進行調整,並且取模。因為 每對 x 與 x' 都相差 p/gcd(a,p),那么根據同余的定義,x 和 x' 關於模 p/gcd(a,p) 同余,所以可以一直取模來調整。而對於 p/gcd(a,p) ,為正時取模才有保證最非負的意義。

注意——位運算超過30位時,盡管變量為long long,也要在之前加上強制轉型(long long)。見代碼的24行......之前我一次比賽,數組初始化是long long類型的,也要在數字后面加上"LL"或" l l "。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 typedef long long LL;
 7 
 8 LL mabs(LL x) {return x>0?x:-x;}
 9 LL exgcd(LL a,LL b,LL& x,LL& y)
10 {
11     if (!b) {x=1,y=0; return a;}
12     LL d,tx,ty;
13     d=exgcd(b,a%b,tx,ty);//bx'+(a%b)y'=1(mod p)
14     x=ty,y=tx-(a/b)*ty;//ay'+b(x'-t*y')=1(mod p)
15     return d;
16 }
17 int main()
18 {
19     LL aa,bb,cc,pp;
20     while (1)
21     {
22       scanf("%I64d%I64d%I64d%I64d",&aa,&bb,&cc,&pp);
23       if (!aa && !bb && !cc && !pp) break;
24       LL a=cc,b=(LL)1<<pp,c=bb-aa,p=(LL)1<<pp;
25       LL d,x,y;//cx=b-a(mod 2^k)-->cx+2^k*y=b-a-->gcd(c,2^k)=1才有解
26       d=exgcd(a,b,x,y);
27       if (c%d!=0) printf("FOREVER\n");
28       else
29       {
30         x=(x*(c/d))%p;//ax+by=c(mod p)的解
31         LL t=mabs(b/d);
32         x=(x%t+t)%t;//最小非負整數解
33         if (!x) x+=t;//為0時要調整
34 printf("%I64d\n",x); 35 } 36 } 37 return 0; 38 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM