虽然不是很理解,看着模版和讲解对这个题改编了一下,就过了。顺便整理一下中国剩余定理当作模版,在网上居然搜到海大wangs的博客了,第一眼居然没看出来,orz大神。。。以下这段话从他博客上复制的。至于原理百度百科吧。。。
设m1,m2,...,mk是两两互素的正整数,对于任意的正整数a1,a2,a3,..,ak 同余方程组:
x≡a1 (mod m1)
x≡a2 (mod m2)
...
x≡ak (mod mk)
必有解, 且解可写为
x≡M1N1a1+MkNkak+....MkNkak (mod m)
其中 m=m1m2m3....mk
Mi=m/mi,(1<=i<=k)
Nj满足MjNj≡1(mod mj),1<=j<=k
即:
Ni,Mi是对模mi的互为逆元。
中国剩余定理代码实现,就是用扩展欧几里得求出n/mi模mi的逆元。就是ext_eulid(n/mi,1)后,求得的x就是逆元。(n代表m数组所有数的乘积)
ans = sum(逆元*n/mi *ai) % n;sum代表求和
这个题代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 #define N 100000 7 int x,y; 8 int ext_eulid(int a,int b) 9 { 10 int t,d; 11 if(b == 0) 12 { 13 x = 1; 14 y = 0; 15 return a; 16 } 17 d = ext_eulid(b,a%b); 18 t = x; 19 x = y; 20 y = t - (a/b)*y; 21 return d; 22 } 23 int main() 24 { 25 int p,e,i,d,num = 0,ans,n; 26 while(scanf("%d%d%d%d",&p,&e,&i,&d)!=EOF) 27 { 28 if(p==-1&&e==-1&&i==-1&&d==-1) break; 29 num ++; 30 ans = 0; 31 printf("Case %d:",num); 32 n = 23*28*33; 33 n/23*ext_eulid(n/23,23); 34 x = (x+23)%23; 35 ans = (ans + p*x*n/23)%n; 36 ext_eulid(n/28,28); 37 x = (x+28)%28; 38 ans = (ans + e*x*n/28)%n; 39 ext_eulid(n/33,33); 40 x = (x+33)%33; 41 ans = (ans + i*x*n/33)%n; 42 if(ans - d > 0) 43 printf(" the next triple peak occurs in %d days.\n",ans-d); 44 else 45 printf(" the next triple peak occurs in %d days.\n",ans+21252-d); 46 } 47 return 0; 48 }
中国剩余定理模版
1 ll x,y; 2 ll ext_eulid(ll a,ll b) 3 { 4 int t,d; 5 if(b == 0) 6 { 7 x = 1; 8 y = 0; 9 return a; 10 } 11 d = ext_eulid(b,a%b); 12 t = x; 13 x = y; 14 y = t - (a/b)*y; 15 return d; 16 } 17 ll CRT(ll *p,ll *o,int num)//p数组代表余数,o数组代表互质的数 18 { 19 int i; 20 ll ans = 0,n = 1; 21 for(i = 1;i <= num;i ++) 22 { 23 n *= o[i]; 24 } 25 for(i = 1;i <= num;i ++) 26 { 27 ext_eulid(n/o[i],o[i]); 28 x = (x+o[i])%o[i]; 29 ans = (ans + n/o[i]*p[i]*x) % n; 30 } 31 return ans; 32 }