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

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

时间:2015-07-26 23:59:26      阅读:402      评论:0      收藏:0      [点我收藏+]

标签:

辗转相除法(欧几里得算法)

时间复杂度:在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;
	} else {
		x = 1; y = 0;
	}
	return d;
}

用于求ax+by=gcd(a,b)整数解,xy返回整数解,extgcd的返回值是ax+by的值。

题目:(A+x*C)%2^k=B 求x整数解。
解析:
x*C=B-A 的在mod(2^k)情况下的整数解
可以转化成x*C+y*(2^k)=B-A的解
通过扩展欧几里得算法求出x1*C+y1*(2^k)=gcd(c,2^k)的解x1,y1,d=x1*C+y1*(2^k)=gcd(c,2^k)
x1*C+y1*(2^k)=(B-A)(gcd(c,2^k)/(B-A))
(A-B)/gcd(c,2^k)*x1*C+(A-B)/gcd(c,2^k)*y1*(2^k)=B-A
x=(A-B)/gcd(c,2^k)*x1
y=(A-B)/gcd(c,2^k)*y1
要求的值为x,x可能是负数,所以要把x变到正整数。通过+(2^k)/d 再%(2^k)/d来变成正数。

 

#include <cstdio>

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

int main()
{
    long long a, b, c, k;
    while (scanf("%lld%lld%lld%lld", &a, &b, &c, &k) != EOF) {
        if (a == 0 && b == 0 && c == 0 && k == 0) break;
        long long x, y;
        long long t = b - a;
        long long h = 1LL << k;  //2^k
        long long g = extgcd(c, h, x, y);
        if (t % g != 0) {      //no solution
            printf("FOREVER\n");
            continue;
        }
        x *= t / g;
        x = (x % (h / g) + (h / g)) % (h / g);//最小非负整数解
        printf("%lld\n", x);
    }
    return 0;
}

  

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

标签:

原文地址:http://www.cnblogs.com/wenruo/p/4678856.html

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