POJ 2115

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2115相关的知识,希望对你有一定的参考价值。

扩展欧几里得

题意:给你一个循环,有初始条件,终止条件,和变量的变化条件,问程序能执行多少次。

example: for(i=A;i!=B;i+=c){statement;}问题是保证所有的计算都在2的k次方以内,也就是说,要模以2^k

这个问题可以抽象成一个函数:A+C*x-y*2^k=B;

把这个函数变形就是:C*x-Y*2^k=B-A;

欧几里得算法求得是:找出一对整数,使得ax+by=gcd(a,b);

定理:1.ax+by=gcd(a,b) ;2.方程右边一定是gcd的倍数,否则没有整数解;3.求出来方程的一个解之后,根据x=(x%l+l)%l 可以求出来方程的最小解,l=b/gcd(a,b);

long long gcd(long long a,long long b,long long &x,long long &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    int d=gcd(b,a%b,y,x);
    y-=x*(a/b);
    return d;
}

上面的程序求出了三个值:一对(x0,y0),还有gcd(a,b),这些都是针对ax+by=gcd(a,b)这个方程的;

先求出右边的数是gcd的多少倍,然后再把x乘以倍数,得到的就是C*x-y*2^k=B-A的其中一个解;

而通解的表达式是(x0+k*b‘,y0-k*a‘),b‘=b/gcd(a,b),a‘=a/gcd(a,b);所以只需要模以k或者b‘就可以了。

代码:

#include<iostream>
#include<queue>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INF 0x3f3f3f3f
using namespace std;

long long gcd(long long a,long long b,long long &x,long long &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    int d=gcd(b,a%b,y,x);
    y-=x*(a/b);
    return d;
}


int main()
{
    long long a,b,c,d;
    int k;
    while(~scanf("%lld%lld%lld%d",&a,&b,&c,&k))
    {
        if(a==0&&b==0&&c==0&&k==0)
        {
            break;
        }
        long long l=1;
        l<<=k;
        long long x,y;
        if((b-a)%(d=gcd(c,l,x,y)))
        {
            printf("FOREVER\n");
            continue;
        }
        k=(b-a)/d;
        x*=k;
        l/=d;
        x=(x%l+l)%l;
        printf("%lld\n",x);
    }
    return 0;
}

 

然后求最小的解的方法就

 

以上是关于POJ 2115的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2115 单变元模线性方程

POJ 2115 C Looooops(exgcd)

poj 2115 Matrix

数学#扩展欧几里德 POJ 1061&2115&2891

POJ 2115 C Looooops

POJ2115 C Looooops