【线性同余方程】toj2297&poj2115 C Looooops

题意:给出a,b,c,k,求x使得(a + x * c) % (2^k) = b.

上述方程即:a + x * c ≡ b(mod (2^k))

左边的a需要化掉,因此两边同减a得到:

x * c ≡ b (mod (2 ^ k)) - a(这里有点滥用同余表示法的味道,望见谅)

右边如果直接(b - a)(mod (2 ^ k))显然可能出现负值,等号就不满足了,为此加上(2 ^k)的若干倍,这样结果就不变,加多少倍呢?加a倍显然是正确的,所以我们加a倍吧,这里随便搞...d当然,根据题意,有a < 2^k,因此加一倍足够了,写的时候没想那么多。。。

于是变成:

x * c ≡ (b - a + (2 ^ k) * a)(mod (2 ^ k))。

做一下变量代换,其实可以表示成:

a * x ≡ b (mod n)(注意,a, b和上边的a,b已经不同)

这就是线性同余方程了。

一、
在数论中,线性 同余方程是最基本的同余方程,“线性”表示方程的未知数次数是一次,即形如:
ax≡b (mod n)的方程。此方程有解当且仅当 b 能够被 a 与 n 的 最大公约数整除(记作 gcd(a,n) | b)。这时,如果 x0 是方程的一个解,那么所有的解可以表示为:
{x0+kn/d|(k∈z)}
其中 d 是a 与 n 的 最大公约数。在模 n 的完全剩余系 {0,1,…,n-1} 中,恰有 d 个解。
二、

对于线性 同余方程
ax ≡ b (mod n) (1)
若 d = gcd(a, n),d  整除 b ,那么b/d为整数。由 裴蜀定理,存在整数对 (r,s) (可用 辗转相除法求得)使得 ar+sn=d,因此 x0=rb/d是方程 (1) 的一个解。其他的解都关于n/d与 x 同余。即x≡x0+(n/d)*t (mod n) (0≤t≤d-1)。
举例来说,方程
12x ≡ 20 (mod 28)
中 d = gcd(12,28) = 4 。注意到 4 = 12 *(-2)+28*1,因此 x0≡5*(-2)≡-10≡4(mod 7)是一个解。对模 28 来说,t=1,x≡4+(28/4)*1≡11 (mod 28);t=2,x≡4+(28/4)*2≡18 (mod 28);t=3,x≡4+(28/4)*3≡25 (mod 28) 。所有的解就是 {4,11,18,25} 。
【摘自 百度百科“线性同余方程”词条

于是我们可以最后得到一个解系x = x0 + m * k(k ∈Z)。其中m = n / d可以唯一确定的。

此题我们理解一下题意,显然需要求出该解系中的最小非负整数解。求出上述所有解显然不靠谱,虽然至多有n / d个,但是在极限条件下这个数会相当大。我们用取余的小技巧:ans = (x0 % m + m) % m.

求解a * r + s * n = d的过程用扩展欧几里得算法即可。具体就不介绍了。

#include <cstdio>
using namespace std;

typedef long long ll;

ll extgcd(ll a, ll b, ll& x, ll& y) {
	ll d = a;
	if (b) {
		d = extgcd(b, a % b, y, x);
		y -= a / b * x;
	} else {
		x = 1;
		y = 0;
	}
	return d;
}

int main() {
	ll a, b, c, d, k, x, y;
	while (~scanf(" %lld %lld %lld %lld", &a, &b, &c, &k) && k) {
		ll n = 1LL << k;
		if ((b - a + n) % (d = extgcd(c, n, x, y))) {
			puts("FOREVER");
		} else {
			x = x * (b - a + n) / d;
			printf("%lld\n", (x % (n / d) + n / d) % (n / d));
		}
	}
	
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值