• POJ2115C Looooops


    转载请注明出处:優YoU    http://user.qzone.qq.com/289065406/blog/1309394009

     

    大致题意:

    对于Cfor(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次才会结束。

    若在有限次内结束,则输出循环次数。

    否则输出死循环。

     

    解题思路:

    题意不难理解,只是利用了 k位存储系统 的数据特性进行循环。

    例如int型是16位的,那么int能保存2^16个数据,即最大数为65535(本题默认为无符号),

    当循环使得i超过65535时,则i会返回0重新开始计数

    i=65534,当i+=3时,i=1

    其实就是 i=(65534+3)%(2^16)=1

     

    有了这些思想,设对于某组数据要循环x次结束,那么本题就很容易得到方程:

    x=[(B-A+2^k)%2^k] /C

    Cx=(B-A)(mod 2^k)  此方程为 模线性方程,本题就是求X的值。

     

    下面将结合《算法导论》第2版进行简述,因此先把上面的方程变形,统一符号。

    a=C  

      b=B-A 

      n=2^k

    那么原模线性方程变形为:

     ax=b (mod n)

    该方程有解的充要条件为 gcd(a,n) | b ,即 b% gcd(a,n)==0

    d=gcd(a,n)

    有该方程的 最小整数解为 x = e (mod n/d)

    其中e = [x0 mod(n/d) + n/d] mod (n/d) x0为方程的最小解

    那么原题就是要计算b% gcd(a,n)是否为0,若为0则计算最小整数解,否则输出FOREVER

     

    当有解时,关键在于计算最大公约数 d=gcd(a,n) 最小解x0

    参考《算法导论》,引入欧几里得扩展方程  d=ax+by

    通过EXTENDED_EUCLID算法(P571)求得dxy值,其中返回的x就是最小解x0,求d的原理是辗转相除法(欧几里德算法)

    再利用MODULAR-LINEAR-EQUATION-SOLVER算法(P564)通过x0计算x值。注意x0可能为负,因此要先 + n/d 再模n/d

    以上方法的推导过程大家自己看《算法导论》。。。这里不证明,只直接使用。

     

    注意:

    计算n=2^k时,用位运算是最快的,1<<k 1左移k位)就是2^k

    但是使用long long的同学要注意格式, 1LL<<k

    使用__int64的同学要强制类型转换 (__int64)1<<k

    不然会WA

     

     

    Source修正:

    CTU Open 2004

    http://contest.felk.cvut.cz/04prg/solved/index.html

     

     

     1 //Memory Time 
    2 //212K 0MS
    3
    4 #include<iostream>
    5 using namespace std;
    6
    7 //d=ax+by,其中最大公约数d=gcd(a,n),x、y为方程系数,返回值为d、x、y
    8 __int64 EXTENDED_EUCLID(__int64 a,__int64 b,__int64& x,__int64& y)
    9 {
    10 if(b==0)
    11 {
    12 x=1;
    13 y=0;
    14 return a; //d=a,x=1,y=0,此时等式d=ax+by成立
    15 }
    16 __int64 d=EXTENDED_EUCLID(b,a%b,x,y);
    17 __int64 xt=x;
    18 x=y;
    19 y=xt-a/b*y; //系数x、y的取值是为满足等式d=ax+by
    20 return d;
    21 }
    22
    23 int main(void)
    24 {
    25 __int64 A,B,C,k;
    26 while(scanf("%I64d %I64d %I64d %I64d",&A,&B,&C,&k))
    27 {
    28 if(!A && !B && !C && !k)
    29 break;
    30
    31 __int64 a=C;
    32 __int64 b=B-A;
    33 __int64 n=(__int64)1<<k; //2^k
    34 __int64 x,y;
    35 __int64 d=EXTENDED_EUCLID(a,n,x,y); //求a,n的最大公约数d=gcd(a,n)和方程d=ax+by的系数x、y
    36
    37 if(b%d!=0) //方程 ax=b(mod n) 无解
    38 cout<<"FOREVER"<<endl;
    39 else
    40 {
    41 x=(x*(b/d))%n; //方程ax=b(mod n)的最小解
    42 x=(x%(n/d)+n/d)%(n/d); //方程ax=b(mod n)的最整数小解
    43 printf("%I64d\n",x);
    44 }
    45 }
    46 return 0;
    47 }

  • 相关阅读:
    数组元素循环右移
    备忘录模式笔记
    调度算法(笔记)
    meta http-equiv的用法(转)
    常用Maven插件介绍(下)(转)
    常用Maven插件介绍(上)(转)
    maven命令
    JDK并发包
    线程基础
    Jav堆排序
  • 原文地址:https://www.cnblogs.com/lyy289065406/p/2122794.html
Copyright © 2020-2023  润新知