R - C Looooops POJ - 2115 (exgcd)

题目大意:很好理解,一个for循环语句,从a开始到b结束,步长是c,模数是pow(2,k)

     问,最少循环多少次,才能到达b,如果永远都到不了b,输出FOREVER

题解:其实就是求一个线性方程,cx=b( mod p)。问x最小是多少。

这个线性方程怎么来的呢?从a开始假设我们走了x步,到达了b,则a+cx=b( mod p)将a移到右边可得cx=(b-a)( mod p)。

这个线性方程怎么解呢? 假设cx在取了y次模得到了(b-a),那么cx-py=(b-a),也就是解这个二元一次方程。

很容易想到用EXGCD。然后就是关于x的最小值,计算出x后,只需要去一次模就可以了。

code:

//#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll; 
void exgcd(ll a,ll b,ll &x,ll &y){ 
    if(b==0) {
        x=1;y=0;
    }
    else {
        exgcd(b,a%b,y,x);
        y-=a/b*x;
    }
}
int main(){
    ll A,B,C,k;
    while(cin>>A>>B>>C>>k){
        if(A==0&&B==0&&C==0&&k==0) break; 
        ll p=(ll)1<<k;
        ll b=B-A;
        ll c=C;
        if(c==0&&A!=B){
            cout<<"FOREVER"<<endl;
            continue ;
        }
        if(b%__gcd(c,p)==0){
            ll d=__gcd(c,p);
            b/=d;c/=d;p/=d;
            ll x,y;
            exgcd(c,p,x,y);x=x*b%p;
            cout<<(x+p)%p<<endl;
        }
        else puts("FOREVER");
    } 
    return 0;
}

对拓展欧里解决线性问题的总结:

  1 类似于:ax+by=c.该方程有解的条件是 c%gcd(a,b)=0,然后a1=a/gcd(a,b),b1=b/gcd(a,b),c1=c/gcd(a,b),将方程转换成了a1x+b1y=c1。然后我们可以根据exgcd求出a1x+b1y=1时的x,然后只需要让x*=c1就是该方程的解,注意,这个解只是其中一个,该方程的通解为x=x+k*b,y=y-k*a。

猜你喜欢

转载自www.cnblogs.com/Accepting/p/12584386.html