POJ 2115
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 2115相关的知识,希望对你有一定的参考价值。
扩展欧几里得
题意:给你一个循环,有初始条件,终止条件,和变量的变化条件,问程序能执行多少次。
example: for(i=A;i!=B;i+=c){statement;}问题是保证所有的计算都在2的k次方以内,也就是说,要模以2^k
这个问题可以抽象成一个函数:A+C*x-y*2^k=B;
把这个函数变形就是:C*x-Y*2^k=B-A;
欧几里得算法求得是:找出一对整数,使得ax+by=gcd(a,b);
定理:1.ax+by=gcd(a,b) ;2.方程右边一定是gcd的倍数,否则没有整数解;3.求出来方程的一个解之后,根据x=(x%l+l)%l 可以求出来方程的最小解,l=b/gcd(a,b);
long long gcd(long long a,long long b,long long &x,long long &y) { if(!b) { x=1; y=0; return a; } int d=gcd(b,a%b,y,x); y-=x*(a/b); return d; }
上面的程序求出了三个值:一对(x0,y0),还有gcd(a,b),这些都是针对ax+by=gcd(a,b)这个方程的;
先求出右边的数是gcd的多少倍,然后再把x乘以倍数,得到的就是C*x-y*2^k=B-A的其中一个解;
而通解的表达式是(x0+k*b‘,y0-k*a‘),b‘=b/gcd(a,b),a‘=a/gcd(a,b);所以只需要模以k或者b‘就可以了。
代码:
#include<iostream> #include<queue> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #define INF 0x3f3f3f3f using namespace std; long long gcd(long long a,long long b,long long &x,long long &y) { if(!b) { x=1; y=0; return a; } int d=gcd(b,a%b,y,x); y-=x*(a/b); return d; } int main() { long long a,b,c,d; int k; while(~scanf("%lld%lld%lld%d",&a,&b,&c,&k)) { if(a==0&&b==0&&c==0&&k==0) { break; } long long l=1; l<<=k; long long x,y; if((b-a)%(d=gcd(c,l,x,y))) { printf("FOREVER\n"); continue; } k=(b-a)/d; x*=k; l/=d; x=(x%l+l)%l; printf("%lld\n",x); } return 0; }
然后求最小的解的方法就
以上是关于POJ 2115的主要内容,如果未能解决你的问题,请参考以下文章