HDU-1573 X问题 中国剩余定理

传送门

 给出n组数,每一组代表x%ai = bi 。 求解x在mm的范围内的数量。因为所有的ai不是互质的,所以直接上模板 求出最小的非负整数解x(对于a*x + b*y = c 的等式,x的每次增长的是 b/gad(a,b) ),之后只要判断在n以内出现的次数就可以了。

#include <iostream>
#include <stdio.h>
#include<algorithm>
#define LL long long
#define maxn 100050
using namespace std;
LL m[maxn];
LL a[maxn];
LL gcd(LL a,LL b)
{
	if(b==0)
	return a;
	return gcd(b,a%b);
}
LL exgcd(LL a,LL b,LL &x,LL &y) {
	if(b==0) {
		x = 1;
		y = 0;
		return a;
	} else {
		LL r = exgcd(b,a%b,y,x);
		y -= x*(a/b);
		return r;
	}
}
LL CRT(LL *a,LL *m,int  n) {
	LL c = a[0], l = m[0];
	LL d, x, y;
	for(int i = 1; i < n; i++) {
		d=exgcd(l, m[i],  x, y);
		if((a[i]-c)%d)
			return -1;
		x = (a[i] - c) / d * x % (m[i] / d);
		c += l * x;
		l = l / d * m[i];
		c %= l;
	}
	return c > 0 ? c : c + l;
}
int main() {
	int n;
	int t;
	scanf("%d",&t);
	while(t--) {
		int mm;
		scanf("%d%d",&mm,&n);
		int lcm=1;
		for(int i=0; i<n; i++)
		{
			scanf("%lld",&m[i]);//m数组存放的是除数 
			lcm=lcm/gcd(lcm,m[i])*m[i];
		}
		for(int i=0; i<n; i++)
			scanf("%lld",&a[i]);d// a数组存放的是余数 
		LL ans=CRT(a,m,n);
		if(ans==-1||ans>mm)//如果不存在这样的 或者 这个数小于mm范围 
		{
			printf("0\n");
			continue;
		}
		if(ans==0)
		printf("%lld\n",(mm-ans)/lcm);// 如果这个数是0 
		else
		{
			printf("%lld\n",(mm-ans)/lcm+1);// 这样的加一是 加上x本身 
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/henucm/article/details/89451891
今日推荐