204. 表达整数的奇怪方式

题目链接

204. 表达整数的奇怪方式

给定 \(2n\) 个整数 \(a_1,a_2,…,a_n\)\(m_1,m_2,…,m_n\),求一个最小的非负整数 \(x\),满足 \(\forall i \in [1,n],x \equiv m_i(mod\ a_i)\)

输入格式

\(1\) 行包含整数 \(n\)

\(2…n+1\) 行:每 \(i+1\) 行包含两个整数 \(a_i\)\(m_i\),数之间用空格隔开。

输出格式

输出最小非负整数 \(x\),如果 \(x\) 不存在,则输出 \(-1\)
如果存在 \(x\),则数据保证 \(x\) 一定在 \(64\) 位整数范围内。

数据范围

\(1 \le a_i \le 2^{31}-1\),
\(0 \le m_i < a_i\)
\(1 \le n \le 25\)

输入样例:

2
8 7
11 9

输出样例:

31

解题思路

扩展中国剩余定理

假设已经求出了前 \(k-1\) 个方程的一个特解 \(x\),设 \(m=lcm(a_1,a_2,\dots,a_{k-1})\),则其通解为 \(x+k\times m\)(其中 \(k\) 为整数),现在需要考虑第 \(k\) 个方程,即要找到这样的一个 \(t\),使得 \(x+t\times m\equiv b_k(\bmod a_k)\),即 \(t\times m\equiv b_k-x(\bmod a_k)\),利用扩展欧几里得即可求解这样的 \(t\),在利用扩欧通解更新 \(x\),同时更新 \(m\),最后的 \(x\) 即为答案

  • 时间复杂度:\(O(mlogn)\)

代码

// Problem: 表达整数的奇怪方式
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/206/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=30;
int n,a[N],b[N];
LL res;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
	if(!b)
	{
		x=1,y=0;
		return a;
	}
	LL d=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return d;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    bool f=true;
    res=b[1];
    LL lcm=a[1];
    for(int i=2;i<=n;i++)
    {
    	LL x,y;
    	LL d=exgcd(lcm,a[i],x,y);
    	if((b[i]-res)%d!=0)
    	{
    		f=false;
    		break;
    	}
    	x*=(b[i]-res)/d;
    	LL t=a[i]/d;
    	x=(x%t+t)%t;
    	res+=lcm*x;
    	lcm=(LL)a[i]/d*lcm;
    }
    if(f)
    	printf("%lld",(res%lcm+lcm)%lcm);
    else
    	puts("-1");
    return 0;
}
posted @ 2022-11-16 22:19  zyy2001  阅读(34)  评论(0编辑  收藏  举报