UVA-12169 不爽的裁判(扩展欧几里得算法)

题意:

输入T,x$_{1}$,x$_{3}$,x$_{5}$,······,x$_{2T-1}$,要求输出x$_{2}$,x$_{4}$,x$_{6}$,······,x$_{2T}$

其中,x$_{i}$=(ax$_{i-1}$+b) \, mod \,10001

分析:

可以暴力枚举a和b,但是效率不高。

考虑使用扩展欧几里得算法,枚举a,计算出x$_{2}$,进而根据x$_{3}$=(ax$_{2}$+b) \, mod \,10001计算出b。有了a,b,x$_{2}$,就可以在O(T)时间内计算出整个序列。如果在计算过程中发现和输入矛盾,则这个a是非法的。

那么如何根据扩展欧几里得算法计算出b呢?

根据扩展欧几里得算法,g=gcd(a,b),方程ax+by=g的一组解是(x0,y0),则当c是g的倍数时ax+by=c的一组解是(x0c/g,y0c/g);当c不是g的倍数时无整数解。

即:方程为(a+1)x+10001*y=x$_{3}$-a^{2}x$_{1}$

另外,计算c时可能溢出,因此使用long long。

代码:

#include<iostream>
using namespace std;
typedef long long ll;
int t;
ll a[10001],aa,b,d,x,y,c,m;
bool f;
void gcd(ll a,ll b,ll &d,ll &x,ll &y){
	if(!b){
		d=a;
		x=1;
		y=0;
	}else{
		gcd(b,a%b,d,y,x);
		y-=x*(a/b);
	}
}
int main(){
	cin>>t;
	for(int i=1;i<=2*t-1;i+=2){
		cin>>a[i];
	}
	for(int i=0;i<=10000;i++){
		f=true;
		aa=i;
		gcd(aa+1,10001,d,x,y);
		c=a[3]-aa*aa*a[1];
		if(c%d)
			continue;
		b=x*c/d;
		b=(b%10001+10001)%10001;
		for(ll j=2;j<=2*t&&f;j++){
			m=(aa*a[j-1]+b)%10001;
			if(j&1){
				if(m!=a[j]){
					f=false;
				}
			}else{
				a[j]=m;
			}
		}
		if(f)
			break;
	}
	for(int i=2;i<=2*t;i+=2){
		cout<<a[i]<<endl;
	}
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章