• C Looooops 扩展欧几里得


    /**
    题目:C Looooops
    链接:https://vjudge.net/contest/154246#problem/S
    题意:for(i = a; i!=b; i = (i+c)%(2^k)) statement;  求statement执行的次数。
    思路:
    设:次数为x, 最终A=k*mod+b;
    mod = 2^k;
    
    (a + c*t)%mod = b
    
    a + c*t = mod*k + b;
    
    mod*k - c*t = a-b; //1
    
    c*t - mod*k = b-a; //2
    
    采用第二个式子进行欧几里得处理。我原先第一个错了。保证求解的常数为正数。
    
    以下来源于:http://blog.csdn.net/zhjchengfeng5/article/details/7786595
    
    求解形如 a*x +b*y = c 的通解,但是一般没有谁会无聊到让你写出一串通解出来,都是让你在通解中选出一些特殊的解,
    比如一个数对于另一个数的乘法逆元什么叫乘法逆元?
    这里,我们称 x 是 a 关于 m 的乘法逆元
    
    这怎么求?可以等价于这样的表达式: a*x + m*y = 1
    
    看出什么来了吗?没错,当gcd(a , m) != 1 的时候是没有解的
    这也是 a*x + b*y = c 有解的充要条件: c % gcd(a , b) == 0
    
    接着乘法逆元讲,一般,我们能够找到无数组解满足条件,但是一般是让你求解出最小的那组解,怎么做?
    我们求解出来了一个特殊的解 x0 那么,我们用 x0 % m其实就得到了最小的解了。为什么?
    
    可以这样思考:
    x 的通解不是 x0 + m*t 吗?
    
    那么,也就是说, a 关于 m 的逆元是一个关于 m 同余的,那么根据最小整数原理,一定存在一个最小的正整数,
    它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,这就好解释了。
    
    可能有人注意到了,这里,我写通解的时候并不是 x0 + (m/gcd)*t ,但是想想一下就明白了,gcd = 1,
    所以写了跟没写是一样的,但是,由于问题的特殊性,有时候我们得到的特解 x0 是一个负数,还有的时候我们的 m 也是一个负数这怎么办?
    当 m 是负数的时候,我们取 m 的绝对值就行了,当 x0 是负数的时候,他模上 m 的结果仍然是负数
    (在计算机计算的结果上是这样的,虽然定义的时候不是这样的),这时候,我们仍然让 x0 对abs(m) 取模,
    然后结果再加上abs(m) 就行了,于是,我们不难写出下面的代码求解一个数 a 对于另一个数 m 的乘法逆元:
    */
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <vector>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int inf = 0x3f3f3f3f;
    const int maxn = 1e5+10;
    const double eps = 1e-6;
    ll gcd(ll a,ll b)
    {
        return b==0?a:gcd(b,a%b);
    }
    ll ext_gcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0){
            x = 1, y = 0; return a;
        }
        ll ret = ext_gcd(b,a%b,x,y);
        ll tmp = x;
        x = y;
        y = tmp-a/b*y;
        return ret;
    }
    int main()
    {
        ll a, b, c, k, mod;
        while(scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k)!=EOF&&k)
        {
            ll xx, yy, aa, bb, cc, d;
            mod = 1LL<<k;
            aa = c;
            bb = mod;
            cc = b-a;
            d = gcd(aa,bb);
            if(cc%d!=0){
                printf("FOREVER
    "); continue;
            }
            d = ext_gcd(aa,bb,xx,yy);
            ll t = xx*(cc/d);
            ll add = bb/d;
            if(add<0) add = -add;
            t %= add;
            if(t<0) t+=add;///结果可以为0,所以这里<0;如果题目结果一定>0。那么这里<=0;
            printf("%I64d
    ",t);
    
        }
        return 0;
    }
  • 相关阅读:
    SQL2012远程连接到SQL2008时的问题:已成功与服务器建立连接,但在登陆过程中发生错误。
    常用正则表达式
    ASP.NET不拖控件教程(1)-认识JSON
    ASP.NET服务器控件对应的HTML标签
    Apache Ranger 1.1.0源码导入IDEA并运行调试security-admin web模块
    【JDK源码分析】线程池ThreadPoolExecutor原理解析
    【JDK源码分析】同步工具Exchanger,它的内部实现原理你看懂了吗?
    【JDK源码分析】并发包同步工具Semaphore
    【JDK源码分析】并发包同步工具CountDownLatch
    【JDK源码分析】并发包同步工具CyclicBarrier
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6713277.html
Copyright © 2020-2023  润新知