UVA 12169 Disgruntled Judge
思路:枚举 a ,通过扩展欧几里得算法利用数列前两个值求 b ,排除非整数解的情况,判断该组 a,b 是否满足剩余序列,(注意必须判断整个序列,不能只判断前几个值,时间够用)。
关于数据范围的第一个问题:b 的范围是 [0,10000] 。由通解公式可知b’=b+10001*t(t 为任意整数),只要通解中的一个解满足序列递推公式,则剩余解都满足。可以简单对其模10001(如第21行,此时 b 的范围是 [-10000,10000]),也可以按照题意中 b 的范围 [0,10000] 令 b=(b%10001+10001)%10001 ,但是必须对 b 进行处理,否则会超出 int/long long 的数据范围。
关于数据范围的第二个问题:强制类型转换。long long c=h[2]-(long long)a*a*h[1]; 这句运算如果不加 (long long) 会导致出错,这个问题在之前的题中也经常出现,原因是在计算后一项 a*a*h[1] 时,虽然 a、h[1] 都是 int 类型,但是相乘之后的积几乎一定会超出 int 的范围,所以不能在计算乘积之后将得出的 int 类型再转换成 long long 类型,而是应该把 a、h[1] 都转成 long long 类型再进行乘法运算。加上 (long long) 只是显式地将 a 强制转换成 long long 类型 , 不同类型的数据计算时会隐(zi)式(dong)转换成高(chang)类型的数据。
1 #include <cstdio> 2 using namespace std; 3 4 void exgcd(int a,int b,int & d,int & x,int & y){ 5 if (b==0) {x=1;y=0;d=a;return;} 6 exgcd(b,a%b,d,y,x); 7 y-=x*(a/b); 8 } 9 10 int main(){ 11 12 int n,h[10005],a,d,b,l; 13 scanf("%d",&n); 14 for(int i=1;i<=n;i++) 15 scanf("%d",&h[i]); 16 17 for(a=0;a<10001;a++){ 18 19 exgcd(a+1,10001,d,b,l); 20 long long c=h[2]-(long long)a*a*h[1]; 21 b=(b*c/d)%10001; 22 if (c%d) continue; 23 int f=1; 24 for (int i=1;i<n;i++){ 25 int temp=(((a*h[i]+b)%10001)*a+b)%10001; 26 if (temp!=h[i+1]){ 27 f=0; 28 break; 29 } 30 } 31 if (f) { 32 for (int i=1;i<=n;i++) 33 printf("%d\n",(a*h[i]+b)%10001); 34 return 0; 35 } 36 } 37 }