zoukankan      html  css  js  c++  java
  • 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;
    	} 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
    ");
                continue;
            }
            x *= t / g;
            x = (x % (h / g) + (h / g)) % (h / g);//最小非负整数解
            printf("%lld
    ", x);
        }
        return 0;
    }
    

      

    
    
  • 相关阅读:
    1.1图形验证码的生成
    1.3蓝图导入问题
    1.2数据库迁移
    1.1首页显示
    1.3 日志配置以及蓝图的抽取
    1.2 app工厂以及db问题的解决
    每日总结
    每日总结
    每日总结
    每日总结
  • 原文地址:https://www.cnblogs.com/wenruo/p/4678856.html
Copyright © 2011-2022 走看看