点击:https://vjudge.net/problem/24843/origin
题目大意:
有一个递推公式xi=(a*x(i-1)+b)mod10001,a<=10000
然后给出一个T,x从1~2*T,输入x1,x3,x5,........。让输出满足公式的x2,x4,x6.......
如果有多种答案,输出任意一组。
题解:首先这个题通过暴力查找a,b就能过。(自己都没敢这样想,还是通过看博客才知道的)。
另一种办法是正解;就是关于扩展欧几里得和模运算的知识,既然a,b都不知道,怎么也得遍历查找一个吧,那就遍历查找a,然后根据递推公式求出b,那怎么求b呢,因为涉及到取模,所以不能直接移项求出。
对于x2: x2=(a*x1+b)mod10001
对于x3: x3=(a*x2+b)mod10001
两个式子结合一下得出:
x3=(a*(a*x1+b)mod10001+b)mod10001
x3=(a*(a*x1+b)+b)mod10001
x3+k*10001=a*a*x1+(a+1)*b./// 因为是取模了,所以k倍的10001+x3==a*a*x1+(a+1)*b
移项得x3-a*a*x1=(a+1)*b+10001*(-k)
另c=x3-a*a*x1
a=(a+1);
b=10001;
x=b;
y=(-k);
式子变成 c=a*x+b*y
可以看出是扩展欧几里得来求原式中的b的;
到这里整个题就算是解决了,剩下的就是用a,b判断符合不符合就行了
当然了,要取扩展欧几里得有解的值才行,有解的判断 c%d==0
暴力:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int q[205];
int main()
{
int n;
scanf("%d",&n);
for(int i=1; i<=2*n; i+=2)
{
scanf("%d",&q[i]);
}
int flag;
for(int a=0;a<=10000;a++)
{
for(int b=0;b<=10000;b++)
{
flag=1;
for(int i=2;i<=2*n;i++)
{
if(i%2==0)
{
q[i]=(a*q[i-1]+b)%10001;
}
else
{
if(q[i]!=(a*q[i-1]+b)%10001)
{
flag=0;
break;
}
}
}
if(flag)break;
}
if(flag)break;
}
for(int i=2;i<=2*n;i+=2)
{
printf("%d\n",q[i]);
}
return 0;
}
扩展欧几里得:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL q[205];
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()
{
int n;
scanf("%d",&n);
for(int i=1; i<=2*n; i+=2)
{
scanf("%lld",&q[i]);
}
for(LL a=0;; a++)
{
LL b,k,d;
LL c=q[3]-a*a*q[1];
gcd(10001,a+1,d,k,b);
if(c%d)continue;///c%d==0才表示有解
b=b*c/d;
int flag=1;
for(int i=2; i<=2*n; i++)
{
if(i%2==0)
{
q[i]=(a*q[i-1]+b)%10001;
}
else
{
if(q[i]!=(a*q[i-1]+b)%10001)
{
flag=0;
break;
}
}
}
if(flag)break;
}
for(int i=2; i<=2*n; i+=2)
{
printf("%lld\n",q[i]);
}
return 0;
}