【luogu P1495】【模板】中国剩余定理(CRT)/曹冲养猪(数论)

【模板】中国剩余定理(CRT)/曹冲养猪

题目链接:luogu P1495

题目大意

给你一些条件,要你找最小的 x,使得满足它被一些数取模的答案是要求的数。
且模数相互都是互质的。
在这里插入图片描述

思路

我们考虑我们先让每个式子单独找数满足,这个很好找,我们可以找到 x 1 , x 2 , . . . x n x_1,x_2,...x_n x1,x2,...xn
那你考虑搞 x 1 + x 2 x_1+x_2 x1+x2,看他能不能同时满足两个式子。
那你要想,那你为了不破坏余数,那你 x 2 x_2 x2 要是 a 1 a_1 a1 的倍数, x 1 x_1 x1 要是 a 2 a_2 a2 的倍数。

那你以此类推,变成所有的加起来,那就是要 x 1 x_1 x1 a 2 , a 3 , . . . , a n a_2,a_3,...,a_n a2,a3,...,an 的倍数, x 2 x_2 x2 a 1 , a 3 , . . . , a n a_1,a_3,...,a_n a1,a3,...,an 的倍数,.……。
这个很好找,就先搞出所有 a a a 的最小公倍数,然后除去 a i a_i ai 就行。

那接着你 x i x_i xi 还要满足模 a i a_i ai b i b_i bi,那这一步要怎么处理呢?
那你要求 LCM × m ≡ b i (   m o d     a i ) \text{LCM}\times m\equiv b_i(\bmod\ a_i) LCM×mbi(mod ai)
不如先求 LCM × m ≡ 1 (   m o d     a i ) \text{LCM}\times m\equiv 1(\bmod\ a_i) LCM×m1(mod ai),然后再拿结果乘 b i b_i bi
然后不难看出 m m m 就是 LCM \text{LCM} LCM 关于 a i a_i ai 的逆元。

那你就求得了 x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1,x2,...,xn
加起来就是一个解了。

但是我们要求最小解,那我们考虑通解。
那模 a i a_i ai 的余数什么时候回循环一次呢?(完全匹配的那种)
不难想到是 lcm { a i } \text{lcm}\{a_i\} lcm{ai} 个循环一次。
那就把答案模 L C M LCM LCM 就可以了。

代码

#include<cstdio>
#define ll long long

using namespace std;

int n;
ll a[11], b[11], LCM, X;

ll gcd(ll x, ll y) {
	if (!y) return x;
	return gcd(y, x % y);
}

ll exgcd(ll a, ll b, ll &x, ll &y) {//exgcd 求逆元
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	
	ll re = exgcd(b, a % b, y, x);
	y -= x * (a / b);
	return re;
}

int main() {
	scanf("%d", &n);
	LCM = 1;
	for (int i = 1; i <= n; i++) {
		scanf("%lld %lld", &a[i], &b[i]);
		LCM = LCM * a[i] / gcd(LCM, a[i]);//求积
	}
	
	for (int i = 1; i <= n; i++) {
		ll mi = LCM / a[i];
		ll x = 0, y = 0;
		exgcd(mi, a[i], x, y);
		X += b[i] * mi * ((x % a[i] + a[i]) % a[i]);//注意 x 有可能是负数
	}
	
	printf("%lld", X % LCM);
	
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一道经典的组合数学题目,需要用到组合数的性质。 我们可以先考虑 $n=5$ 的情况。这时,一共有 $2^n=32$ 种可能的抛硬币的结果,其中正面朝上的硬币数为 $0,1,2,3,4,5$ 的情况分别有 $1,5,10,10,5,1$ 种。 接下来,我们考虑 $n$ 的任意情况。可以证明,当 $n$ 为偶数时,正面朝上的硬币数的种数与 $n=5$ 时是相同的;当 $n$ 为奇数时,正面朝上的硬币数的种数比 $n=5$ 时多一种。这是因为当抛硬币的次数为偶数时,正反面的数量是相等的,因此正面朝上的硬币数的种数与 $n=5$ 时相同;当抛硬币的次数为奇数时,正反面的数量不相等,因此正面朝上的硬币数的种数比 $n=5$ 时多一种。 因此,需要分别处理 $n$ 为奇数和偶数的情况。当 $n$ 为偶数时,正面朝上的硬币数的种数与 $n=5$ 时相同,因此答案为: $$ \sum_{i=0}^{n/2} \binom{n}{i} $$ 当 $n$ 为奇数时,正面朝上的硬币数的种数比 $n=5$ 时多一种,因此答案为: $$ \sum_{i=0}^{n/2} \binom{n}{i} + \sum_{i=0}^{n/2} \binom{n}{i+1} $$ 需要注意的是,当 $n$ 为 $0$ 时,只有一种可能的结果,即所有硬币都是反面朝上,因此答案为 $1$。 以下是一份参考代码,可以用于计算答案: ```c++ #include <iostream> #include <cmath> using namespace std; int main() { int n; cin >> n; if (n == 0) { cout << "1" << endl; } else { int ans = pow(2, n); if (n % 2 == 0) { for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i) * (1 << i) / (i + 1); } } else { for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i) * (1 << i) / (i + 1); } for (int i = 0; i <= n / 2; i++) { ans -= 2 * pow(-1, i) * pow(2, n - i - 1) * (1 << i) / (i + 1); } } cout << ans << endl; } return 0; } ``` 代码中使用了数学公式计算答案,其中 $\binom{n}{i}$ 使用了移项后再计算的方式,避免了复杂的组合数计算。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值