Looooops(线性同余方程, exgcd)

34 篇文章 1 订阅
21 篇文章 0 订阅

题目描述
一个C语言的for循环:

    for(int i=A;i!=B;i+=C)st;

其中i表示变量,A、B和C分别表示初值、终值和步长,st表示循环体。
要求计算当循环变量i运算在k位无符号整数体系下(运算值范围:0~2^k-1,此时,i+=c溢出后截断),循环体st会执行多少次?

输入格式
输入每组数据包括4个整数A,B,C和k。

输出格式
对于每组数据,输出循环次数,如果永远不能结束,输出FOREVER。

输入样例

1 3 2 4
1 5 2 4
1 2 4 3
0 0 0 0

输出样例

1
2

FOREVER
数据范围

1≤k≤32。
0≤A, B, C≤2^k。

思路:
题意很容易联想到取模运算
设 m = 1<<k;
则可列出 A + xC %m == B 如果 只需找到x的最小解即可
转换得 A + x * C + y * m == B
又得 x * C + y * m == B - A 利用exgcd解出x, y 即可
并且B - A 为 gcd(C, m)的整数倍时方程有解,
对该条件进行解释:
原方程化为:ax + kn = b (设k为某一整数)
那么如果a与n的最大公约数为d,那么ax + kn 必然可以提取一个d的因子,也就是说b必然有d这个因子,所以如果b%d!=0,说明b没有d这因子,与前面的结论相互矛盾,所以无解.

如果解出x, y 且(B - A) % gcd(C, m) == 0 ;
此时的x, y 是在 x*C + y * m == gcd(C, m) 解出的, 令 t = (B - A) / gcd(C, m)
而方程 x * C + y * m == B - A的解为 x1 = x * t , y1 = y * t;
又由线性同余方程的通解ax + by == gcd(a, b), x = x0 + k1(a/gcd(a, b)), y = y0 - k2(b/gcd(a, b)
所以本题中的x1最小解即为令 z = m / gcd(c, m) 则 Xmin = (x1 % z + z) % z,(防止为负数)
更多细节见于代码

#include <bits/stdc++.h>

using namespace std;
#define ll long long
/*
A + xC % K == B
A + xc + yk == B
xc + yk == B - A
如果 x * c + y * k == kd == B - A
x = x0 + k(a / gcd(a, b))

 */
ll exgcd(ll a, ll b, ll &x, ll &y) // 在求出x, y的同时求出gcd(a, b)
{// ax + by == gcd(a, b) = gcd(b, a % b) = bx + a%b * y = b*x + (a - a/b*b)*y = a*y - b*(x - a/b * y)
	if(b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
}

int main()
{
	ll a, b, c;
	int k;
	while(cin >> a >> b >> c >> k && k)
	{
		ll x, y;
		ll z = 1ll<<k;
		ll d = exgcd(c, z, x, y);
		if((b - a) % d != 0)
		{
			cout << "FOREVER" << endl;
			continue;
		}
		x *= (b - a) / d; // 因为之前的x是按照gcd(c, z)算出来的, 而gcd(c, z)不一定是等于b - a的, 所以要乘以其倍数
		z /= d;
		cout << (x % z + z) % z << endl; // 防止x是负数
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值