UVa 12169 - Disgruntled Judge(拓展欧几里德)

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3321

 

题意:

有个裁判出的题太难,总是没人做,所以他很不爽。有一次他终于忍不住了,
心想:“反正我的题没人做,我干嘛要费那么多心思出题?不如就输入一个随机数,输出一个随机数吧。”
于是他找了3个整数x1、a和b,然后按照递推公式xi = (a * x(i-1) + b) mod 10001计算出了一个长度为2T的数列,
其中T是测试数据的组数。然后,他把T和x1, x3,…, x(2T-1)写到输入文件中,x2, x4,…, x(2T)写到了输出文件中。
你的任务就是解决这个疯狂的题目:输入T, x1, x3,…, x(2T-1),输出x2, x4,…, x(2T)。
输入保证T≤100,且输入的所有x值为0~10000的整数。如果有多种可能的输出,任意输出一个即可。

 

分析:

由题意可得(下面的M为10001,k,k1,k2为任意整数):
x2 = a * x1 + b - k1 * M;
x3 = a * x2 + b - k2 * M;
联立上面两式得 M * k + (-a - 1) * b = a * a * x1 - x3;
所以我们可以枚举a,然后用拓展欧几里德求出b和其他值,再判断可行性即可。

 

代码:

 1 #include <cstdio>
 2 
 3 typedef long long int LLI;
 4 const LLI M = 10001;
 5 int T;
 6 LLI x[100*2+5];
 7 
 8 void exgcd(LLI m, LLI a, LLI& g, LLI& k, LLI& b) { // 拓展欧几里德
 9     if(!a) g = m, k = 1, b = 0;
10     else exgcd(a, m%a, g, b, k), b -= k * (m/a);
11 }
12 
13 bool judge(LLI a) {
14     LLI g, k, b, t = a * a * x[1] - x[3];
15     exgcd(M, -a-1, g, k, b);
16     if(t % g) return false;
17     b *= t / g;
18     for(int i = 2; i <= 2 * T; i++) {
19         LLI j = (a * x[i-1] + b) % M;
20         if(i & 1) {
21             if(x[i] != j) return false;
22         } else x[i] = j;
23     }
24     return true;
25 }
26 
27 int main() {
28     scanf("%d", &T);
29     for(int i = 1; i < 2 * T; i += 2) scanf("%lld", &x[i]);
30     for(LLI a = 0; a < M; a++) if(judge(a)) break;
31     for(int i = 2; i <= 2 * T; i += 2) printf("%lld\n", x[i]);
32     return 0;
33 }

 

posted @ 2018-04-14 01:00  Ctfes  阅读(114)  评论(0编辑  收藏  举报