UVA - 12169 扩展欧几里得

8 篇文章 0 订阅

题目链接

UVA-12169

题意

现在有一个长度为2n的序列B,序列满足 B i = ( a ∗ B i − 1 + b )   m o d   10001 B_i=(a*B_{i-1}+b)\ mod\ 10001 Bi=(aBi1+b) mod 10001,其中a和b两个参数未知。现在给定下标为奇数的序列B,求下标为偶数的序列B。求出任意一个即可.

思路

我们先写一下式子
B 3 = ( a B 2 + b ) % m o d = k 1 m o d + a B 2 + b B_3=(aB_2+b)\%mod=k_1mod+aB_2+b B3=(aB2+b)%mod=k1mod+aB2+b B 2 = ( a B 1 + b ) % m o d = k 2 m o d + a B 1 + b B_2=(aB_1+b)\%mod=k2mod+aB_1+b B2=(aB1+b)%mod=k2mod+aB1+b
把第二个式子带到第一个式子可以的到 B 3 = ( k 1 + a k 2 ) m o d + a 2 B 1 + ( a + 1 ) b B_3=(k_1+ak_2)mod+a^2B_1+(a+1)b B3=(k1+ak2)mod+a2B1+(a+1)b
如果把mod的系数看成一个整体,那么这个式子可以化简为
K m o d + ( a + 1 ) b = B 3 − a 2 B 1 Kmod+(a+1)b=B_3-a^2B_1 Kmod+(a+1)b=B3a2B1
由于a和b的范围都不超过10000,那么我们枚举一下a,就得到一个关于K和b的二元不定方程,利用扩欧求得b后带回原序列进行验证,如果符合公式那么我们就找到了一组合法的a和b,就可以求出偶数序列了。

代码

#include <algorithm>
#include <cstdio>
#include <cstring>
#define inf 1ll << 62
#define cases(yjq) for (int cas = 1; cas <= (int)yjq; ++cas)
using namespace std;
const int mod = 10001;
int n;
long long A[10005], B[10005];
int cnt;
inline long long Abs(long long x) { return x < 0 ? -x : x; }
long long exgcd(long long a, long long b, long long& x, long long& y) {
   if (!b) {
       x = 1;
       y = 0;
       return a;
   }
   int t = exgcd(b, a % b, y, x);
   y -= a / b * x;
   return t;
}

bool solve(long long a, long long b, long long c, long long& x, long long& y) {
   long long g = exgcd(a, b, x, y);
   if (c % g) return false;
   x *= c / g;
   y *= c / g;
   long long tmp = Abs(b / g);
   x = (x % tmp + tmp) % tmp;
   cnt = 0;
   for (int i = 0; x + i * tmp <= 10000; ++i) B[cnt++] = x + i * tmp;
   y = (c - a * x) / b;
   return true;
}
int main() {
   scanf("%d", &n);
   for (int i = 1; i <= n; ++i) scanf("%d", A + i);
   long long x, y;
   int a;
   for (a = 0; a <= 10000; ++a) {
       if (!solve(a + 1, mod, A[2] - 1ll * a * a * A[1], x, y)) continue;
       bool ok = false;
       for (int i = 0; i < cnt; ++i) {
           bool gg = false;
           for (int j = 2; j <= n; ++j) {
               if ((A[j] - a * a * A[j - 1] - a * B[i] - B[i]) % mod != 0) {
                   gg = true;
                   break;
               }
           }
           if (!gg) {
               for (int j = 1; j <= n; ++j) printf("%d\n", (a * A[j] + B[i]) % mod);
               ok = true;
               break;
           }
       }
       if (ok) break;
   }
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值