zoukankan      html  css  js  c++  java
  • C Looooops

    看了半天的同余 扩展欧几里得 练练手

    C Looooops
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 27079   Accepted: 7690

    Description

    A Compiler Mystery: We are given a C-language style for loop of type 
    for (variable = A; variable != B; variable += C)
    
    statement;

    I.e., a loop which starts by setting variable to value A and while variable is not equal to B, repeats statement followed by increasing the variable by C. We want to know how many times does the statement get executed for particular values of A, B and C, assuming that all arithmetics is calculated in a k-bit unsigned integer type (with values 0 <= x < 2k) modulo 2k

    Input

    The input consists of several instances. Each instance is described by a single line with four integers A, B, C, k separated by a single space. The integer k (1 <= k <= 32) is the number of bits of the control variable of the loop and A, B, C (0 <= A, B, C < 2k) are the parameters of the loop. 

    The input is finished by a line containing four zeros. 

    Output

    The output consists of several lines corresponding to the instances on the input. The i-th line contains either the number of executions of the statement in the i-th instance (a single integer number) or the word FOREVER if the loop does not terminate. 

    Sample Input

    3 3 2 16
    3 7 2 16
    7 3 2 16
    3 4 2 16
    0 0 0 0
    

    Sample Output

    0
    2
    32766
    FOREVER

    题目的意思就是 a+bx≡c(mod 2^k)
    典型的线性同余方程 转化为 bx-y*2^k=c-a 当gcd(b,2^k)能整除c-a的时候 就存在解
    通解好求 跑一边exgcd可以得出x0 然后 基础解 x=(c-a)/gcd(b,2^k)*x0; 通解为 x0+zz*(2^k/gcd(2^k,b); 显然当zz=0的时候最小
    关键是要求出最小正整数解。
    对于ax+by=gcd(a,b) 这个方程 我们有通解 x=x0+b/gcd(a,b);
    那么怎么求x的最小正整数解。呢 首先知道一点 b/gcd(a,b)是解的最小区间
    这个怎么理解呢

    假设c为x的解的最小间距,此时d为y的解的间距,所以x=x0+c*t,y=y0-d*t(x0,y0为一组特解,t为任意整数)

          带入方程得:a*x0+a*c*t+b*y0-b*d*t=n,因为a*x0+b*y0=n,所以a*c*t-b*d*t=0,t不等于0时,a*c=b*d

          因为a,b,c,d都为正整数,所以用最小的c,d,使得等式成立,ac,bd就应该等于a,b的最小公倍数a*b/gcd(a,b),

          所以c=b/gcd(a,b),d就等于a/gcd(a,b)。

    所以,若最后所求解要求x为最小整数,那么x=(x0%(b/gcd(a,b))+b/gcd(a,b))%(b/gcd(a,b))即为x的最小整数解。

    x0%(b/gcd(a,b))使解落到区间-b/gcd(a,b)~b/gcd(a,b),再加上b/gcd(a,b)使解在区间0~2*b/gcd(a,b),

    再模上b/gcd(a,b),则得到最小整数解 (转自http://www.xuebuyuan.com/1380732.html) 

    学无止境 挺有意思的这个求最小正整数解的方式

          

    #include <cstdio>
    #include <iostream>
    #include <string>
    
    using namespace std;
    typedef long long ll;
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return a;
        }
        ll temp=exgcd(b,a%b,y,x);
        y-=(a/b)*x;
        return temp;
    }
    ll get(ll k)
    {
        ll temp=1;
        for(int i=1;i<=k;i++)
        {
            temp*=2;
        }
        return temp;
    }
    int main()
    {
        ll a,b,c,k;
        while(cin>>a>>b>>c>>k)
        {
            if(a==0&&b==0&&c==0&&k==0) break;
            ll temp=b-a;
            ll x,y;
            ll zz=get(k);
            //cout<<zz<<endl;
            ll g=exgcd(c,zz,x,y);
            //cout<<g<<endl;
            if(temp%g!=0) cout<<"FOREVER"<<endl;
            else
            {
                ll t=zz/g;//这里有精度问题。。 得多注意
                x=(x*(temp/g)%t+t)%t;// 得到目标的最小解
                cout<<x<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    linux7系统进入单用户模式
    GoAccess日志分析工具
    yum总结
    分布式文件系统---GlusterFS
    【centos7】添加开机启动服务/脚本
    centos 7 服务初始化
    chrony软件
    [USACO4.1]麦香牛块Beef McNuggets 题解报告
    组合数的几种计算方法
    【ZJOI2005】沼泽鳄鱼 题解报告
  • 原文地址:https://www.cnblogs.com/z1141000271/p/7133689.html
Copyright © 2011-2022 走看看