UVa12169 - Disgruntled Judge (扩展欧几里得)

题目链接 : UVa12169 - Disgruntled Judge

解题思路

因为递推公式对10001取模,所以 a,b 的取值范围就可以缩小到 [0,10000], 最简单的就是直接对 a,b 进行 枚举,满足条件就作为正确答案。

代码

#include <iostream>

using namespace std;
const int mod = 10001;
int t, x[210];

void solve()
{
    for(int a=0; a<=10000; a++)
    {
        for(int b=0; b<=10000; b++)
        {
            bool flag = true;
            for(int i=2; i<=2*t; i+=2)
            {
                x[i] = (a*x[i-1] + b) % mod;
                if(i+1<=2*t&&x[i+1]!=((a*x[i]+b)%mod))
                {
                    flag = false;
                    break;
                }
            }
            if(flag) return;
        }
    }
}

int main()
{
    while(cin>>t)
    {
        for(int i=1; i<=2*t; i+=2) cin>>x[i];
        solve();
        for(int i=2; i<=2*t; i+=2) cout<<x[i]<<"\n";
    }
    return 0;
}

利用扩展欧几里得求解

上面的这种做法的效率低的原因就是,当 a 确定是,我们再次枚举了b,而我们观察递推公式,可以利用 x1 x2 和 a 的值直接计算 b 。

x2 =( ax1 + b ) % 10001x3 =( ax2 + b ) % 10001 x3a2x1 = (a+1)b10001n

我们可以枚举 a, 然后利用扩展欧几里得直接算出 b,然后进行验证。由于是直接计算 b 所以值有可能很大,在中间的乘法运算会各种溢出,所以数组改为 long long 类型。

代码

#include <iostream>

using namespace std;
typedef long long ll;
const int mod = 10001;
ll x[210];
int t;

//扩展欧几里得
ll exp_gcd(ll a, ll b, ll &x, ll &y) 
{
    if(b==0)
    {
        x = 1;
        y = 0;
        return a;
    }

    ll g = exp_gcd(b, a%b, x, y);
    ll temp = x;
    x = y;
    y = temp - a / b * y;

    return g;
}

void solve()
{
    for(int a=0; a<mod; a++)
    {
        ll n, b, g;
        ll temp = x[3] - a * a * x[1];

        //计算
        g = exp_gcd(mod, a+1, n, b);
        if(temp%g) continue;
        b = temp / g * b;

        //验证
        bool flag = true;
        for(int i=2; i<=2*t; i+=2)
        {
            x[i] = ((ll)x[i-1] * a + b) % mod;
            if((i+1)<(2*t)&&x[i+1]!=((x[i]*a+b)%mod))
            {
                flag = false;
                break;
            }
        }
        if(flag) return;
    }
}

int main()
{
    while(cin>>t)
    {
        for(int i=1; i<=2*t; i+=2) cin>>x[i];
        solve();
        for(int i=2; i<=2*t; i+=2) cout<<x[i]<<"\n";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值