UVA 12169 Disgruntled Judge (扩展欧几里得算法)

25 篇文章 0 订阅

UVA 12169 Disgruntled Judge (扩展欧几里得算法)

给出3个整数x1,a,b。根据递推公式xi=(a*xi-1+b) mod 10001来构造了长度为2T的数列。给出x1,x3,x5…x2T-1,求出x2,x4,x6…x2T.

根据题意,有:
x2=(ax1+b)%mod - - - 1 1 1
x3=(a
x2+b)%mod - - - 2 2 2

令n=mod
1 1 1得x2和ax1+b同余,所以x2-(ax1+b)=ny1 - - - 3 3 3
2 2 2得x3和ax2+b同余,所以x3-(ax2+b)=ny2 - - - 4 4 4
. . . . .
方法一:
4 4 4- 3 3 3得,ny+(a+1)x2=ax1+x3
通过枚举a的值,通过扩展欧几里得算法求出x2的值,然后再根据 2 2 2
x3=(ax2+b)%mod == ax2+b=k*mod+x3
求出b的值。

方法二:
4 4 4+a× 3 3 3得,ny+(a+1)b=x3-a2x1
通过枚举a的值,通过扩展欧几里得算法求出b的值
. . . . .
最后用O(T)的时间来计算序列,每计算出一个新式就进行校验,发现与原输入不符,则继续枚举a。

值得注意的是,用扩展欧几里得算法求出的x是方程ny+(a+1)x2=gcd(n,a+1)的解,需要通过再一次的变换来得到原方程的解。

在求出原方程的解后,通过解的线性变换 X=k*(n/gcd(n,a+1))+x2来得到处在[0,10000]区间内的解。

进行线性变换的方法可以通过取模进行。
X=(x%mod+mod)%mod,求得X属于[0,10000]

对于X=kmod+x 求X属于[0,mod]
X=x%mod 等价于 x=k
mod+X 等价于 X=kmod+x
由于x可能为负数,固等式变成
X=(x%mod+mod)%mod

对于第一种方法后来求出的b也要在进行计算序列之前通过
b=(b%n+n)%n的操作,将其变换到[0,10000]的同余类。
根据取模的性质,有xi=(axi-1+b)%n=(axi%n+b%n)%n不然可能会溢出。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int max_n=1e4+5;
int n;
int input_x[max_n];
int output_x[max_n];
int mod=10001;
typedef long long ll;
void gcd(int a,int b,int &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(void)
{
//	freopen("out.txt","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&input_x[i]);
	for(int a=0;a<=10000;a++)
	{
		ll y,x;
		ll b;
		int d;//d=gcd(mod,a+1) 
		ll c=input_x[2]-(ll)a*a*input_x[1];
		gcd(mod,a+1,d,y,b);
		if(c%d!=0)continue;
		b*=(c/d);
//		b=(b%mod+mod)%mod;
		bool flag=true;
		for(int i=1;i<=n;i++)
		{
			output_x[i]=(int)(((ll)a*input_x[i]+b)%mod);
			int temp=(int)(((ll)a*output_x[i]+b)%mod);
			if(i!=n&&temp!=input_x[i+1]){
				flag=false;break;
			}
		}
		if(!flag)continue;
		else{
			for(int i=1;i<=n;i++)
			printf("%d\n",output_x[i]);
			break;
		}
	}
// fclose(stdout);
 } 
//3
//17
//822
//3014
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值