POJ - 2115C Looooops 扩展欧几里得(做的少了无法一眼看出)

题目大意&&分析:

for (variable = A; variable != B; variable += C)
  statement;这个循环式子表示a+c*n(n为整数)==b是停止循环,题目中要求(a+c*n)%2^k=b时停止循环;所以我们可以得到一个形如ax+by=c的方程式:a+c*n=b+2^k*m;通过移项:c*x-2^k*m=b-a;可以直接套exgcd模板了:

代码:
#include <iostream>

using namespace std;
typedef long long ll;
ll d;
ll x,y;
void exgcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if (!b)
    {
        x=1;y=0;d=a;return ;
    }
    else
    {
        exgcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
}
int main()
{
    ll a,b,c,k;
    while (cin>>a>>b>>c>>k&&(a+b+c+k))
    {
        ll C=(ll)1<<k;                //注意别写成ll k=(ll)1<<k; 会出错就是了;

        exgcd(c,C,d,x,y);
        //cout<<x<<y<<endl;
        if ((b-a)%d)
        {
            cout<<"FOREVER"<<endl;
        }
        else
        {
            x=x*(b-a)/d;
            C/=d;                    //1
            x=(x%C+C)%C;              //2
            cout<<x<<endl;
        }
    }
}

这两行用于求出最小正整数解,ax+by=c;  a,b互素,则ax1+by1=ax2+by2;那么(x1-x2)一定是b的整数倍,

所以当x>0时,x%b即为所求;

x<0时,x%b+b即为所求,二者综合就是(x%b+b)%b可以得出最小正整数解;

时间: 2024-10-14 18:39:17

POJ - 2115C Looooops 扩展欧几里得(做的少了无法一眼看出)的相关文章

POJ 2115 C Looooops(扩展欧几里得应用)

题目地址:POJ 2115 水题..公式很好推.最直接的公式就是a+n*c==b+m*2^k.然后可以变形为模线性方程的样子,就是 n*c+m*2^k==b-a.即求n*c==(b-a)mod(2^k)的最小解.(真搞不懂为什么训练的时候好多人把青蛙的约会都给做出来了,这题却一直做不出来.....这两道不都是推公式然后变形吗.....) 代码如下: #include <iostream> #include <cstdio> #include <string> #incl

poj2115 C Looooops——扩展欧几里得

题目:http://poj.org/problem?id=2115 就是扩展欧几里得呗: 然而忘记除公约数... 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll A,B,C,k,a,b,x,y,g,s; ll gcd(ll a,ll b){return a%b?gcd(b,a%b):b;} void exgc

poj 1061 同余方程+扩展欧几里得+(求最小非负整数解)

题目可以转化成求关于t的同余方程的最小非负数解: x+m*t≡y+n*t (mod L) 该方程又可以转化成: k*L+(n-m)*t=x-y 利用扩展欧几里得可以解决这个问题: eg:对于方程ax+by=c 设tm=gcd(a,b) 若c%tm!=0,则该方程无整数解. 否则,列出方程: a*x0+b*y0=tm 易用extend_gcd求出x0和y0 然后最终的解就是x=x0*(c/tm),y=y0*(c/tm) 注意:若是要求最小非负整数解? 例如求y的最小非负整数解, 令r=a/tm,则

POJ 2115 C Looooops(扩展欧几里得)

辗转相除法(欧几里得算法) 时间复杂度:在O(logmax(a, b))以内 int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b); } 扩展欧几里得算法 时间复杂度和欧几里得算法相同 int extgcd(int a, int b, int& x, int& y) { int d = a; if (b != 0) { d = extgcd(b, a % b, y, x); y -= (a / b) * x;

POJ 2115-C Looooops(扩展欧几里德)

C Looooops Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17981   Accepted: 4694 Description A Compiler Mystery: We are given a C-language style for loop of type for (variable = A; variable != B; variable += C) statement; I.e., a loop w

青蛙的约会 - poj 1061(扩展欧几里得)

分析:这个东西在数论里面应该叫做不定方程式,可以搜一下,有很精彩的证明,先求出来方程式的一组特解,然后用这组特解来求通解,但是求出来特解之后怎么求这些解里面的最小非负x值?我们知道 x = x0 + bt, 假设x=0, 也就是最小值, 那么 t = x0/(-b), x0+x0/(-b)*b就是最小值了,当然如果结果是负的加上一个b即可. 代码如下: ========================================================================

【扩展欧几里得】BZOJ1477-青蛙的约会

一直在WA,后来我发现我把东西看反了-- [题目大意] 给出一个长度为L的环状坐标轴,两个点开始时位于(X,0).(Y,0).每次两点分别往右边移动m和n,问能否相遇? [思路] 由题意,可得: X+mt=Y+nt(mod L) (X+mt)-(Y+nt)=L*k (n-m)t+L*k=X-Y. 可以用扩展欧几里得来做.具体来说,显然要满足n-m和L的最大公约数(记为d)要整除X-Y,否则无解.这个可以在扩展欧几里得中求出. 式子可以化简为:[(n-m)/d]*t+(L/d)*k=(X-Y)/d

POJ - 2115 - C Looooops (扩展欧几里得)

C Looooops Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19826   Accepted: 5299 Description A Compiler Mystery: We are given a C-language style for loop of type for (variable = A; variable != B; variable += C) statement; I.e., a loop w

POJ 2115 (模线性方程 -&gt; 扩展欧几里得)

题意: for(i=A ; i!=B ;i +=C)循环语句,问在k位操作系统中循环结束次数. 若在有则输出循环次数. 否则输出死循环. 存在这样的情况:i= 65533 :i<=2:i+= 4:时i = 2: 由模线性方程->扩展欧几里得 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using