首页 > 代码库 > 韩信点兵
韩信点兵
P1272 - 韩信点兵
Description
韩信是中国军事思想“谋战”派代表人物,被后人奉为“兵仙”、“战神”。“王侯将相”韩信一人全任。“国士无双”、“功高无二,略不世出”是楚汉之时人们对其的评价。作为统帅,他率军出陈仓、定三秦、擒魏、破代、灭赵、降燕、伐齐,直至垓下全歼楚军,无一败绩,天下莫敢与之相争。
相传,韩信带兵打仗时,从不直接清点军队人数。有一次,韩信带1500名兵士打仗,战死四五百人。站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韩信马上说出人数:1049。
这次,刘邦派韩信带兵N人攻打一座重兵驻扎的城市。城市占领了,可汉军也是伤亡惨重。韩信需要知道汉军至少损失了多少兵力,好向刘邦汇报。
已知韩信发出了M次命令,对于第i次命令,他选择一个素数Pi,要求士兵每Pi人站一排,此时最后一排剩下了aiai
人。你的任务是帮助韩信求出这种情况下汉军损失兵力的最小值。当然,由于士兵们都很疲惫,他们有可能站错队伍导致韩信得到的数据有误。
Input
第一行两个正整数N,M,分别代表最初的军队人数和韩信的询问次数。
接下来有M行,每行两个非负整数$Pi,,
ai$,代表韩信选择的素数和此时剩下的人数。
输入保证每个素数各不相同。
Output
输出一行,一个整数。
若有解,输出最小损失人数。若无解,输出-1.
Sample Input
1500 3
3 2
5 4
7 6
Sample Output
31
Hint
对于30%的数据,1≤N≤1,000,000,1≤M≤4;
对于50%的数据,1≤N≤100,000,000,1≤M≤8;
对于100%的数据,1≤N≤1,000,000,000,000,1≤M≤10;保证所有素数的乘积≤10121012
, 0≤ai≤Pi.
Source
数论,欧几里得,中国剩余定理
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #define ll long long 7 using namespace std; 8 const int N=1001; 9 ll m[N],r[N]; 10 int n; 11 ll gcd(ll a,ll b) { 12 return a%b==0 ? b : gcd(b,a%b); 13 } 14 void exgcd(ll a,ll b,ll& x,ll& y) { 15 if(!b) x=1,y=0; 16 else { 17 exgcd(b,a%b,x,y); 18 ll tmp=x; 19 x=y; 20 y=tmp-a/b*y; 21 } 22 } 23 ll solve() { 24 ll M=m[1],R=r[1]; 25 for(int i=2;i<=n;i++) { 26 ll d=gcd(M,m[i]); 27 ll c=r[i]-R; 28 if(c%d) return -1; 29 ll k1,k2; 30 exgcd(M/d,m[i]/d,k1,k2); 31 k1=(c/d*k1) % (m[i]/d); 32 R=R+k1*M; 33 M=M/d*m[i]; 34 R%=M; 35 } 36 while (R<=0) R+=M; 37 return R; 38 } 39 int main() { 40 41 cin>>n; 42 for(int i=1;i<=n;i++) cin>>m[i]>>r[i]; 43 printf("%lld",solve()); 44 return 0; 45 46 }
韩信点兵