題目鏈接: http://www.51nod.com/onlineJudge/user.html#!userId=21687
題意: 中文題誒~
思路: 本題就是個中國剩余定理模板題,不過模擬也可以過,而且時間復雜度嘛~
我們可以知道gcd得出兩個數的最大公約在最壞的情況下(a, b是相鄰的兩個斐波拉契數)是O(logn)的, 同理可以知道exgcd也是O(lgn)時間復雜度,因此中國剩余定理時間復雜度是O(nlogn); 而模擬的話最壞的情況下需要O(n*x)的時間~本題兩種算法都是15ms...
這里給出一個關於gcd時間復雜度分析的博客: http://blog.csdn.net/zeroonet/article/details/53375313
我們先說一下模擬.首先我們知道如果x%a=m的話, x=k*a+m.
對於 x%a1=m1, 很顯然x(min)=m, 如果再加一組條件 x%a2=m2, 若當前x(min)不滿足條件2的話, 我們找下一個(我們可以想象滿足條件1的數據升序排列)滿足條件1的數據,即a1+m,再判斷其是否滿足條件2, 很顯然我們只要地推下去就能找到同時滿足條件1, 2的最小數據; 如果再加一個條件 x%a3=m3呢? 前面我們已經招到了滿足條件1, 2的最小數據
x(min), 若其不滿足條件3話, 我們找下一個滿足條件1, 2的數據, 即x(min)+lcm(a1, a2)(此題中ai與aj互質,所以直接相乘就好啦,並且由這里我們不難看出最壞情況下即每次加2時其時間復雜度為O(x)), 再判斷其是否滿足條件3, 最終我們可以招到同時滿足三個條件的最小數;
那么,很明顯對於要滿足n個這樣的條件的答案我們也可以用這個方法求到啦~
代碼:
1 #include <bits/stdc++.h>
2 #define MAXN 20
3 #define ll long long
4 using namespace std; 5
6 int main(void){ 7 int n; 8 ll p[MAXN], m[MAXN], ans=0, gg=1; 9 scanf("%d", &n); 10 for(int i=0; i<n; i++){ 11 scanf("%lld%lld", &m[i], &p[i]); 12 } 13 ans=p[0]; 14 for(int i=0; i<n-1; i++){ 15 gg*=m[i]; 16 while(ans%m[i+1]!=p[i+1]){ 17 ans+=gg; 18 } 19 } 20 printf("%lld\n", ans); 21 return 0; 22 }
那么中國剩余定理的模板呢~
至於證明嘛, 暫時還沒想到(望路過的大神教一下)~
代碼:
1 #include <bits/stdc++.h>
2 #define MAXN 20
3 #define ll long long
4 using namespace std; 5
6 ll p[MAXN], m[MAXN]; 7 int n; 8
9 void exgcd(ll a, ll b, ll& x, ll& y){ //exgcd求乘法取模運算的逆元 10 if(!b){ 11 y=0, x=1; 12 return; 13 }else{ 14 exgcd(b, a%b, x, y); 15 ll temp=x; 16 x=y; 17 y=temp-a/b*y; 18 } 19 } 20
21 ll crt(void){ 22 ll M=1, ans=0; 23 for(int i=0; i<n; i++){ 24 M*=m[i]; 25 } 26 for(int i=0; i<n; i++){ 27 ll mi=M/m[i], x, y; 28 exgcd(mi, m[i], x, y); 29 ans=(ans+p[i]*x*mi)%M; 30 } 31 if(ans<0){ 32 ans+=M; 33 } 34 return ans; 35 } 36
37 int main(void){ 38 scanf("%d", &n); 39 for(int i=0; i<n; i++){ 40 scanf("%lld%lld", &m[i], &p[i]); 41 } 42 printf("%lld\n", crt()); 43 return 0; 44 }