题目描述:
第一行和第二行输入8个数字,对应每一位第二行都小于第一行,求最小的值 x x x令 x x x对第一行每一位取余后等于第二行 ( x 不 小 于 第 一 行 的 每 个 数 ) (x不小于第一行的每个数) (x不小于第一行的每个数)
题目分析:
首先有式子 x x x% a = b a=b a=b, x x x% c = d c=d c=d,先设第一个满足条件的 x x x为 x 1 x1 x1对于每个满足题意的 x x x,都有 x = n ∗ L C M ( a , c ) + x 1 x=n*LCM(a,c)+x1 x=n∗LCM(a,c)+x1, L C M ( a , c ) LCM(a,c) LCM(a,c)为 a a a和 c c c的最小公倍数,这点可以自行证明。此时令 m = L C M ( a , c ) m=LCM(a,c) m=LCM(a,c)。
随后,若引入一个新的 e , f e,f e,f有 x x x% e = f e=f e=f,则 x x x要在满足 x = n ∗ L C M ( a , c ) + x 1 x=n*LCM(a,c)+x1 x=n∗LCM(a,c)+x1的情况下查找满足新式子的最小 x 2 x2 x2,随后更新 m m m,因为之后满足的 x x x与 x 2 x2 x2的差值又要满足被 a , c , e a,c,e a,c,e整除,因此就要将 m m m更新为 m = L C M ( m , e ) m = LCM(m,e) m=LCM(m,e),以此类推,求得最后一个满足的最小 x x x即为答案。
复杂度大概是ans除一个阶乘吧,不太好算,但是比暴力枚举快一些
代码:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<string.h>
#include<math.h>
typedef long long ll;
using namespace std;
int m, n;
struct P {
int a, b;
}p[8];
bool cmp(P a, P b) {
return a.a < b.a;
}
int gcd(int a, int b) {//gcd模板,求最大公约数
return (b ? gcd(b, a % b) : a);
}
int lcm(int a, int b) {//根据gcd求最小公倍数
return a / gcd(a, b) * b;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);//c++操作,不用管他
for (int i = 0; i < 8; i++) cin >> p[i].a;
for (int i = 0; i < 8; i++) cin >> p[i].b;//两行输入
m = p[0].a, n = p[0].b + p[0].a; int j;//初始化,此时m每次加第一个a,n为满足第一对的最小值
for (int i = 1; i < 8; i++) {
for (j = n; ; j += m) {//j被初始化为当前最小值每次加m
if (j % p[i].a == p[i].b && j % p[i - 1].a == p[i - 1].b) {//判断成立,更新n和m,退出当前层循环
n = j, m = lcm(m, p[i].a); break;
}
}
}
cout << n << endl;
return 0;
}
/*
2 3 5 7 11 13 17 19
1 2 4 6 10 12 16 18
*/