H Hello Kiki

来源:互联网 发布:电脑按java干什么 编辑:程序博客网 时间:2024/05/07 13:28

H  Hello Kiki

Description

One day I was shopping in the supermarket.There was a cashier counting coins seriously when a little kid running andsinging "门前大桥下游过一群鸭,快来快来 数一数,二四六七八". And then the cashier put the counted coins back morosely andcount again...

Hello Kiki is such a lovely girl that sheloves doing counting in a different way. For example, when she is counting Xcoins, she count them N times. Each time she divide the coins into several same sized groups and write down the groupsize Mi and the number of the remaining coins Ai on her note.

One day Kiki's father found her note and hewanted to know how much coins Kiki was counting.

Input

The first line is T indicating the numberof test cases.

Each case contains N on the first line,Mi(1 <= i <= N) on the second line, and corresponding Ai(1 <= i <=N) on the third line.

All numbers in the input and output areintegers.

1 <= T <= 100, 1 <= N <= 6, 1<= Mi <= 50, 0 <= Ai < Mi

Output

For each case output the least positiveinteger X which Kiki was counting in the sample output format. If there is nosolution then output -1.

 Sample Input

2

2

14 57

5 56

5

19 54 40 24 80

11 2 36 20 76

 Sample Output

Case 1: 341

Case 2: 5996

——写自Jun Chen 

    这道题目是中国剩余定理的应用,一开始的时候没有注意数据情况,以为是纯中国剩余定理,直接用公式就可以了,谁知道第二组数据居然没有结果输出!后来才发现题目中M[i]之间可以不互素,所以不能直接用公式做!但是在不互素的情况下也不是就一定就无解,也可能存在解的!如果互素的话,那是一定存在解的!
首先以两个同余方程组成的方程组为例:
   n = n1 (mod m1) and
   n = n2 (mod m2)
 有解的前提条件是gcd(m1, m2) | (n2 - n1)
 1) 用扩展欧几里德算法计算t * m1 + s * m2 = gcd(m1, m2) = d
 2) 计算tt, ss使其满足tt * m1 + ss * m2 = n2 - n1
 具体方法是tt = t * (n2 - n1) / d,ss = s * (n2 - n1) / d
 3) 那么nn = tt * m1 + n1 = -ss * m2 + n2 (这两个用哪个都行)
 4) 我们已经把两个同余方程组变成了一个:
  n = nn (mod LCM(m1, m2))
 重复这个过程,每次合并两个方程,就可以解决整个方程组了
代码如下:

#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <iostream>#include <algorithm>#include <vector>#include <map>#include <set>using namespace std;int T, N;__int64 M[1005], A[1005];void exgcd(__int64 m, __int64 n, __int64 &d, __int64 &x, __int64 &y) //扩展的欧几里德算法;{    if (n == 0) {        d = m, x = 1, y = 0;    } else {        exgcd(n, m % n, d, y, x);//在刘汝佳的算法入门经典中的方法;        y -= x * (m / n);    }}__int64 mod(__int64 x, __int64 n){ return (x % n + n) % n; }/*x = a1 (mod m1)x = a2 (mod m2)a1 + m1 * p1 = a2 + m2 * p2a2 - a1 = m1 * p1 - m2 * p2d = gcd(m1, m2) = m1 * q1 + m2 * q2p1 = q1 * (a2 - a1) / dx = a1 + m1 * p1 (mod LCM(m1, m2))*/bool reduce(__int64 a1, __int64 m1, __int64 a2, __int64 m2, __int64 &aa, __int64 &mm){    __int64 d, q1, q2;    exgcd(m1, m2, d, q1, q2);    if ((a2 - a1) % d == 0) {//存在解的情况;    __int64 p1 = q1 * ((a2 - a1) / d);    mm = m1 * (m2 / d);    aa = mod(a1 + m1 * p1, mm);    return true;}return false;}bool check(__int64 X) {for (int i = 0; i < N; ++i)if (X % M[i] != A[i])return false;return true;}int main(){cin >> T;for (int id = 1; id <= T; ++id){cin >> N;for (int i = 0; i < N; ++i)cin >> M[i];for (int i = 0; i < N; ++i)    cin >> A[i];__int64 aa, mm;bool ok = true;if (N == 1) {aa = A[0], mm = M[0];} else {ok &= reduce(A[0], M[0], A[1], M[1], aa, mm);for (int i = 2; i < N && ok; ++i)ok &= reduce(A[i], M[i], aa, mm, aa, mm);}if (aa == 0) aa += mm;cout << "Case " << id << ": " << (ok ? aa : -1) << endl;}    return 0;}    


原创粉丝点击