题目链接: 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 }