在京州电子科技大学,学生们做了一个游戏叫碧绿航线参加某青春比赛;这个游戏中,一艘船有六种属性:火力,航空,雷装,装填,航速,耐久。第i属性的周期分别为ai天,每艘船的每个属性在其周期中的某一天会达到顶峰。为了通关6-4来获得椿,我们需要这艘船在每个属性上都达到顶峰。我们记录了一艘船每个属性某次顶峰的时间为第bi天,我们想知道之后(如果今天就可以也算)第一个可能达到去6-4要求的时间为多少。其中ai互质。
第一行6个正整数表示ai(1≤ai≤20)
第二行6个整数表示bi(1≤bi≤1,000,000)
输出一个整数表示答案
2 3 5 7 11 13 1 1 1 1 1 1
1
这题是一道关于中国剩余定理的模板题,相当于要找到一个数n,使n对1<=i<=6满足n % ai=bi,设n=n1+n2+n3+n4+n5+n6,其中ni满足ni % ai==bi,且对1<=j<=6,j!=i有ni%j==0,即ni是所有aj(j!=i)的公倍数,设M=a1*a2*a3*a4*a5*a6,因为ai两两互质,故M是其最小公倍数,则有ni是(M/ai)的倍数.
所以,现在有两个条件:
1.ni%ai==bi
2.ni%(M/ai)==0
又有,M/ai与ai互质,故gcd(M/ai,ai)=1,用扩展欧几里得算法e_gcd(M/ai,ai,x,y),有x*M/ai+y*ai=1 , 等式两边%ai,有:
(x*M/ai)%ai=1
故(bi*x*M/ai)%ai==bi,且(bi*x*M/ai)%(M/ai)==0.
发现其满足条件1,2,故bi*x*M/ai就是我们要找的ni,即ni=bi*x*M/ai,最后n再n=n%M
本题有一个坑,就是n对任意1<=i<=6需要满足n>=bi,故设maxb为最大的一个bi,while(n<maxb)n+=M.
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
#include<string.h>
const int Max = 64000000;
bool flag1[Max];
long long gcd(long long a, long long b)
{
if (b != 0)
return gcd(b, a%b);
else
return a;
}
long long exGcd(long long a, long long b, long long &x, long long &y)
{
if (b == 0)
{
x = 1; y = 0;
return a;
}
long long r = exGcd(b, a%b, x, y);
long long t = x; x = y; y = t - a / b*y;
return r;
}
int main()
{
long long ai[7];
long long bi[7], lrm1[7], lrm2;
long long i, maxb, j, k;
while (scanf("%lld", &ai[1]) != EOF)
{
maxb = 0;
for (i = 2; i <= 6; i++)
scanf("%lld", &ai[i]);
for (i = 1; i <= 6; i++)
{
scanf("%lld", &bi[i]);
maxb = max(bi[i], maxb);
bi[i] = bi[i] % ai[i];
if (bi[i] == 0)
bi[i] = ai[i];
}
lrm2 = 1;
for (i = 1; i <= 6; i++)
lrm2 *= ai[i];
for (i = 1; i <= 6; i++)
lrm1[i] = lrm2 / ai[i];
// cout << lrm2 << endl;
long long sum = 0;
long long temp;
for (i = 1; i <= 6; i++)
{
long long x, y;
temp = lrm1[i];
exGcd(lrm1[i], ai[i], x, y);
temp *= x;
// while (temp%ai[i] != bi[i])
// temp += lrm1[i];
temp *= bi[i];
lrm1[i] = temp;
sum += temp;
}
sum %= lrm2;
if (sum == 0)
sum = lrm2;
// cout << sum << " " << maxb << endl;
temp = sum;
while (temp < maxb)
{
temp += lrm2;
}
sum = temp;
cout << sum << endl;
}
return 0;
}