POJ 2115 C Looooops Exgcd 数论专题第十二题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88873627

title

POJ 2115
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

Source

扫描二维码关注公众号,回复: 5698752 查看本文章

CTU Open 2004

analysis

刚开始的时候,我是直接暴算的,想着循环次数就是 ( C A ) / B (C-A)/B ,然后特判一下 ( C A ) (C-A) 是否小于零,。。。然后样例的第三个就没过,哦,然后上网查了一下,发现我的思想稍微转化一下就是:
A + C x = B ( m o d   2 k ) C x = B A ( m o d   2 k ) A+Cx=B(mod \text{ }2^{k}) → Cx=B-A(mod\text{ } 2^{k}) ,然后就可以用拓展欧几里德方法求出gcd最大公因数,再利用同余性质转化,求同余方程,或者不定方程。

先将方程化为一般形式: A x = C ( m o d   k ) A x + k y = C Ax=C(mod \text{ }k) → Ax+ky=C 。若 g c d ( A , k ) C gcd(A,k)|C ,就可以利用 A x + k y = g c d ( A , B ) ( m o d   k ) [ m o d   k ] Ax+ky=gcd(A,B)(mod\text{ } k) [一般没有mod\text{ } k] ,再把变量 x , y x,y 乘上 C / g c d ( A , B ) C/gcd(A,B) 就是答案了。而要求最小正整数解,就是根据 A x + k y = g c d ( A , k ) A ( x + k / g c d ( A , k ) ) + ( y A / g c d ( A , k ) = g c d ( A , k ) Ax+ky=gcd(A,k) → A(x+k/gcd(A,k))+(y-A/gcd(A,k)=gcd(A,k) ,所有的 x x&#x27; 都满足 x + k / g c d ( A , k ) x+k/gcd(A,k) 来进行调整,并且取模。因为 每对 x x x x&#x27; 都相差 k / g c d ( A , k ) k/gcd(A,k) ,那么根据同余的定义, x x x x&#x27; 关于模 k / g c d ( A , k ) k/gcd(A,k) 同余,所以可以一直取模来调整。而对于 k / g c d ( A , k ) k/gcd(A,k) ,为正时取模才有保证最非负的意义。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
inline ll mabs(ll x)
{
	return x>0?x:-x;
}
inline ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if (!b)
    {
        x=1,y=0;
        return a;
    }
    ll r=exgcd(b,a%b,x,y);
	ll tmp=x;
    x=y;
    y=tmp-a/b*y;
    return r;
}
int main()
{
	while (1)
	{
		ll aa,bb,cc,kk;
		read(aa);read(bb);read(cc);read(kk);
		if (!aa && !bb && !cc && !kk) break;
		ll a=cc,b=(ll)1<<kk,c=bb-aa,k=(ll)1<<kk;
		if (!c)
		{
			puts("0");
			continue;
		}
		ll x,y;
		ll gcd=exgcd(a,b,x,y);
		if (c%gcd) puts("FOREVER");
		else
		{
			x=(x*(c/gcd))%k;
			ll t=mabs(b/gcd);
			x=(x%t+t)%t;
			if (!x) x+=t;
			printf("%lld\n",x);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/88873627