P3868 [TJOI2009] 猜数字

题目描述

现有两组数字,每组 k k k 个。

第一组中的数字分别用 a 1 , a 2 , ⋯   , a k a_1,a_2,\cdots ,a_k a1,a2,,ak 表示,第二组中的数字分别用 b 1 , b 2 , ⋯   , b k b_1,b_2,\cdots ,b_k b1,b2,,bk 表示。

其中第二组中的数字是两两互素的。求最小的 n ∈ N n\in \mathbb{N} nN,满足对于 ∀ i ∈ [ 1 , k ] \forall i\in [1,k] i[1,k],有 b i ∣ ( n − a i ) b_i | (n-a_i) bi(nai)

输入格式

第一行一个整数 k k k

第二行 k k k 个整数,表示: a 1 , a 2 , ⋯   , a k a_1,a_2,\cdots ,a_k a1,a2,,ak

第三行 k k k 个整数,表示: b 1 , b 2 , ⋯   , b k b_1,b_2,\cdots ,b_k b1,b2,,bk

输出格式

输出一行一个整数,为所求的答案 n n n

样例 #1

样例输入 #1

3
1 2 3
2 3 5

样例输出 #1

23

提示

对于 100 % 100\% 100% 的数据:

1 ≤ k ≤ 10 1\le k \le 10 1k10 ∣ a i ∣ ≤ 1 0 9 |a_i|\le 10^9 ai109 1 ≤ b i ≤ 6 × 1 0 3 1\le b_i\le 6\times 10^3 1bi6×103 ∏ i = 1 k b i ≤ 1 0 18 \prod_{i=1}^k b_i\le 10^{18} i=1kbi1018

每个测试点时限 1 1 1 秒。

注意:对于 C/C++语言,对 64 64 64 位整型数应声明为 long long

若使用 scanfprintf函数(以及 fscanffprintf等),应采用 %lld标识符。

题目分析

b i ∣ ( n − a 1 ) ⇔ b i × k = n − a i ( k ∈ Z ) ⇔ n = b i × k + a i ⇔ n ≡ a i ( m o d b i ) b_i \mid (n - a_1) \\ \Leftrightarrow b_i \times k = n - a_i(k \in \mathbb Z) \\ \Leftrightarrow n = b_i \times k + a_i \\ \Leftrightarrow n \equiv a_i \pmod {b_i} bi(na1)bi×k=nai(kZ)n=bi×k+ainai(modbi)

裸的 CRT。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define int __int128

using namespace std;

inline int read()
{
	int w = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		w = (w << 1) + (w << 3) + (ch ^ 48);
		ch = getchar();
	}
	return w * f;
}

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

const int maxk = 15;
int k, a[maxk], b[maxk];
int M = 1;
int c[maxk], inv[maxk];
int ans = 0;

int exgcd(int a, int b, int &x, int &y)
{
	if (b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	int d, x1 = 0, y1 = 0;
	d = exgcd(b, a % b, x1, y1);
	x = y1, y = x1 - a / b * y1;
	return d;
}

void crt()
{
	for (int i = 1; i <= k; i++)
	{
		c[i] = M / b[i];
	}
	for (int i = 1; i <= k; i++)
	{
		int x = 0, y = 0;
		exgcd(c[i], b[i], x, y);
		inv[i] = (x % b[i] + b[i]) % b[i];
	}
	for (int i = 1; i <= k; i++)
	{
		ans += (a[i] * c[i] * inv[i]) % M;
		ans %= M;
	}
}

signed main()
{
#ifndef ONLINE_JUDGE
#define LOCAL
	//freopen("in.txt","r",stdin);
#endif
	k = read();
	for (int i = 1; i <= k; i++)
	{
		a[i] = read();
	}
	for (int i = 1; i <= k; i++)
	{
		b[i] = read();
		M *= b[i];
	}
	crt();
	write(ans);
	puts("");
#ifdef LOCAL
	fprintf(stderr, "%f\n", 1.0 * clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值