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;
} 

 

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