1. 程式人生 > >[補檔]各種奇怪的韓信問題

[補檔]各種奇怪的韓信問題

open one class 鏈接 -a type 感覺 gif 由於

這是兩道奇怪的韓信問題

韓信點兵&喪心病狂的韓信大點兵

T1 [COGS 1786]韓信點兵

題目

  韓信是中國軍事思想“謀戰”派代表人物,被後人奉為“兵仙”、“戰神”。“王侯將相”韓信一人全任。“國士無雙”、“功高無二,略不世出”是楚漢之時人們對其的評價。作為統帥,他率軍出陳倉、定三秦、擒魏、破代、滅趙、降燕、伐齊,直至垓下全殲楚軍,無一敗績,天下莫敢與之相爭。   相傳,韓信帶兵打仗時,從不直接清點軍隊人數。有一次,韓信帶1500名兵士打仗,戰死四五百人。站3人一排,多出2人;站5人一排,多出4人;站7人一排,多出6人。韓信馬上說出人數:1049。   這次,劉邦派韓信帶兵N人攻打一座重兵駐紮的城市。城市占領了,可漢軍也是傷亡慘重。韓信需要知道漢軍至少損失了多少兵力,好向劉邦匯報。   已知韓信發出了M次命令,對於第i次命令,他選擇一個素數Pi,要求士兵每Pi人站一排,此時最後一排剩下了ai人。你的任務是幫助韓信求出這種情況下漢軍損失兵力的最小值。當然,由於士兵們都很疲憊,他們有可能站錯隊伍導致韓信得到的數據有誤

INPUT

  第一行兩個正整數N,M,分別代表最初的軍隊人數和韓信的詢問次數。   接下來有M行,每行兩個非負整數Pi,ai,代表韓信選擇的素數和此時剩下的人數。   輸入保證每個素數各不相同

OUTPUT

  輸出一行,一個整數。   若有解,輸出最小損失人數。若無解,輸出-1.

SAMPLE

INPUT

1500 3 3 2 5 4 7 6

OUTPUT

31

解題報告

  CRT裸題   CRT:中國剩余定理(中國單身狗定理)   設正整數m1,m2,...,mk兩兩互素,則同余方程組     x≡a1 (mod m1)     x≡a2 (mod m2)     x≡a3 (mod m3)      . . . . . .     x≡ak (mod mk)   有整數解,並且在模M=m1×m2×...×mk下的解是唯一的,解為     x≡(a1×M1×ny(M1)+...+ak×Mk×ny(Mk))mod M   其中Mi=M/mi,而ny(Mi)為Mi模mi的逆元   代碼如下: 技術分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 typedef long long L;
 6 L n;
 7 int m;
 8 L a[11],mod[11];
 9 L M(1),ans(0);
10 inline void extend_gcd(L a,L b,L &x,L &y){
11     if(b==0){
12         x=1;
13         y=0;
14         return
; 15 } 16 extend_gcd(b,a%b,x,y); 17 L tmp(x); 18 x=y; 19 y=tmp-(a/b)*y; 20 } 21 inline L CRT(L a[],L m[],int n){ 22 for(int i=1;i<=n;i++) 23 M*=m[i]; 24 for(int i=1;i<=n;i++){ 25 L x,y; 26 L Mi(M/m[i]); 27 extend_gcd(Mi,m[i],x,y); 28 ans=(ans+M+Mi*x*a[i])%M; 29 } 30 //if(ans<0) 31 // ans+=M; 32 return ans; 33 } 34 inline int gg(){ 35 freopen("HanXin.in","r",stdin); 36 freopen("HanXin.out","w",stdout); 37 scanf("%lld%d",&n,&m); 38 for(int i=1;i<=m;i++) 39 scanf("%lld%lld",&mod[i],&a[i]); 40 L ans(CRT(a,mod,m)); 41 if(ans>n){ 42 puts("-1"); 43 return 0; 44 } 45 while(ans<n) 46 ans+=M; 47 ans-=M; 48 printf("%lld",n-ans); 49 } 50 int k(gg()); 51 int main(){;}
View Code 需要註意的是,要求的是最小損失人數,稍微處理一下結果即可

[COGS 2160]喪心病狂的韓信大點兵

題目

  懶得粘了,上鏈接= =   http://cogs.pro/cogs/problem/problem.php?pid=2160   這道題顯然不能用普通的CRT做,因為它們不互質   此時我們就要采用兩兩合並的思想,假設要合並如下兩個方程     x=a1+m1x1     x=a2+m2x2   那麽得到     a1+m1x1=a2+m2x2 ? m1x1+m2x2=a2-a1   再利用擴展歐幾裏得解出x1的最小整數解,再代入    x=a1+m1x1 得到x後,合並為一個方程的結果為 y≡x(mod lcm(m1,m2)) 這樣一直合並下去,最終可以求得解 代碼如下: 技術分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 typedef long long L;
 6 int m;
 7 L a[21],mod[21];
 8 inline L gcd(L a,L b){
 9     return a%b?gcd(b,a%b):b;
10 }
11 inline L ext_gcd(L a,L b,L &x,L &y){
12     if(b==0){
13         x=1;
14         y=0;
15         return a; 
16     }
17     L gcd(ext_gcd(b,a%b,x,y));
18     L tmp(x);
19     x=y;
20     y=tmp-(a/b)*y;
21     return gcd;
22 }
23 inline L ny(L a,L b){
24     L x,y;
25     L gcd(ext_gcd(a,b,x,y));
26     if(gcd!=1)
27         return -1;
28     return (x%b+b)%b;
29 }
30 inline bool merge(L a1,L m1,L a2,L m2,L &a3,L &m3){
31     L d(gcd(m1,m2));
32     L c=a2-a1;
33     if(c%d)
34         return false;
35     c=(c%m2+m2)%m2;
36     m1/=d;
37     m2/=d;
38     c/=d;
39     c*=ny(m1,m2);
40     c%=m2;
41     c*=m1*d;
42     c+=a1;
43     m3=m1*m2*d;
44     a3=(c%m3+m3)%m3;
45     return true;
46 }
47 L CRT(L a[],L m[],int n){
48     L a1(a[1]),m1(m[1]);
49     for(int i=2;i<=n;i++){
50         L a2(a[i]),m2(m[i]),a3,m3;
51         if(!merge(a1,m1,a2,m2,a3,m3))
52             return -1;
53         a1=a3;
54         m1=m3;
55     }
56     return (a1%m1+m1)%m1;
57 }
58 inline int gg(){
59     freopen("weakhanxin.in","r",stdin);
60     freopen("weakhanxin.out","w",stdout);
61     scanf("%d",&m);
62     for(int i=1;i<=m;i++)
63         scanf("%lld%lld",&mod[i],&a[i]);
64     printf("%lld",CRT(a,mod,m));
65 }
66 int k(gg());
67 int main(){;}
View Code ps:這份代碼是目前COGS上rk1的代碼,在各種0.002s中出現一個0.000s,讓我這個鶸鷄感覺有些方= =

[補檔]各種奇怪的韓信問題