码迷,mamicode.com
首页 > 其他好文 > 详细

POJ 2115

时间:2016-02-23 13:03:18      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:

扩展欧几里得

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

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

标签:

原文地址:http://www.cnblogs.com/qioalu/p/5209249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!