曹冲养猪
给定若干对表示x≡b_i,a_i两两互质,求
正文
/*
原题:曹冲养猪 (经典中国剩余定理)
题意:给定若干对 (a_i,b_i) 表示 x ≡ b_i (mod a_i),a_i 两两互质,求最小正整数解 x。
思路:中国剩余定理合并:先算总模 M=∏a_i,再逐项累加 b_i·(M/a_i)·inv(M/a_i, a_i)。
题目保证 a_i 两两互质,故逆元必存在;合并结果恰为 0 时输出 M(最小正整数)。
复杂度:时间 O(n·log a_i),空间 O(1)。
易错点:答案可能超过 64 位,需用 __int128 累加;输出要求最小正整数(解为 0 时取 M)。
*/
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using i128=__int128;
ll exgcd(ll a, ll b, ll &x, ll &y){
if(b==0){
x=1;
y=0;
return a;
}
ll x1, y1;
ll g=exgcd(b, a%b, x1, y1);
x=y1;
y=x1-(a/b)*y1;
return g;
}
ll inv(ll a, ll m){
ll x, y;
exgcd(a, m, x, y);
return ((x%m)+m)%m;
}
void print_i128(i128 x){
if(x==0){
cout<<0;
return;
}
string s;
while(x>0){
s+=char('0'+(int)(x%10));
x/=10;
}
reverse(s.begin(), s.end());
cout<<s;
}
int main(){
int n;
cin>>n;
i128 M=1;
vector<ll> a(n), b(n);
for(int i=0;i<n;i++){
cin>>a[i]>>b[i];
M*=a[i];
}
i128 ans=0;
for(int i=0;i<n;i++){
i128 Mi=M/a[i];
ll t=inv((ll)(Mi%a[i]), a[i]);
i128 term=b[i]%M;
term=term*(Mi%M)%M;
term=term*t%M;
ans=(ans+term)%M;
}
if(ans==0){
ans=M;
}
print_i128(ans);
cout<<"\n";
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring