Disgruntled Judge UVA - 12169 (数论 之 扩展欧几里得+模运算)

点击: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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值