Disgruntled Judge UVA - 12169(扩展欧几里得应用+暴力)
题目给我们的输入数值都是序列中的单数项,我们已知递推公式xi=(aXi-1 + b)mod10001,
所以我们可以将X2表示为X2=(aX1 + b)mod10001,将X3表示为X3=(aX2 + b)mod10001
然后将X2的式子带入到X3中得:X3=(a(aX1 + b)mod10001 + b)mod10001
X3=(a(aX1 + b)+ b)mod10001
X3+10001*k=a*a*X1+a*b+b
10001(-k)+(a+1)b=X3-a*a*X1 ——1式
推导出上式之后,我们发现上式与ax+by=c(2式)这个式子格式一样,所以我们可以用扩展欧几里得算法来进行求解
因为1式中的a,b,-k都是未知数,所以我们可以通过枚举a的值来进行求解。
1式中的10001,-k,(a+1),b ,X3-a*a*X1分别对应2式中的a,x,b,y,c
我们通过扩展欧几里得算法,可以求出gcd(10001,a+1),如果gcd不是c的整数倍的话,则式子无解,可以继续枚举别的a
如果是整数倍的话,则可以用扩展欧几里得算法算出来的b求出1式中的b,这样我们就可以算出通过公式算出序列中的每个单项了
如果求出来的单项与输入不符合,则说明这个a不是正确的a,然后继续枚举别的a
因为递推公式对10001取模,所以a是0~10000的数,所以枚举所有a,时间也够。
1 #include<iostream> 2 3 typedef long long ull; 4 const int maxn = 200 + 20; 5 6 using namespace std; 7 8 void gcd(ull a, ull b, ull &d, ull &x, ull &y); 9 10 int main() 11 { 12 ios::sync_with_stdio(false); 13 cin.tie(0); 14 cout.tie(0); 15 16 int T; 17 ull p[maxn]; 18 cin >> T; 19 for (int i = 1; i < 2*T; i+=2) 20 { 21 cin >> p[i]; 22 } 23 24 for (int a = 1096;a<=10000; a++) 25 { 26 ull k,b,d; 27 ull t =p[3]-a * a*p[1]; 28 gcd(10001,a+1, d, k, b); 29 if (t%d)//如果不是倍数,则无解 30 continue; 31 32 bool flag = true; 33 b = b * t / d;//我们需要通过算法算出来的b,乘以相应的倍数得到递推式中的b 34 for (int i = 2; i <= 2 * T; i++)//通过递推公式算出单项,验证a是否合法 35 { 36 if (i & 1) 37 { 38 if (p[i] != (a*p[i - 1] + b) % 10001) 39 { 40 flag = false; 41 break; 42 } 43 } 44 else 45 p[i] = (a*p[i - 1] + b) % 10001; 46 } 47 48 if (flag == true) 49 break; 50 } 51 52 for (int i = 2; i <= 2 * T; i += 2) 53 cout << p[i] << endl; 54 55 56 return 0; 57 } 58 59 void gcd(ull a, ull b, ull &d, ull &x, ull &y) 60 { 61 if (!b) 62 { 63 d = a; 64 x = 1; 65 y = 0; 66 } 67 else 68 { 69 gcd(b, a%b, d, y, x); 70 y -= x * (a / b); 71 } 72 }