HDU 1573 X问题 - BenFromHRBUST

HDU 1573 X问题

Problem Description

求在小于等于N的正整数中有多少个X满足:X mod a[0] = b[0], X mod a[1] = b[1], X mod a[2] = b[2], …, X mod a[i] = b[i], … (0 < a[i] <= 10)。

Input

输入数据的第一行为一个正整数T,表示有T组测试数据。每组测试数据的第一行为两个正整数N,M (0 < N <= 1000,000,000 , 0 < M <= 10),表示X小于等于N,数组a和b中各有M个元素。接下来两行,每行各有M个正整数,分别为a和b中的元素。

Output

对应每一组输入,在独立一行中输出一个正整数,表示满足条件的X的个数。

Sample Input

3
10 3
1 2 3
0 1 2
100 7
3 4 5 6 7 8 9
1 2 3 4 5 6 7
10000 10
1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8 9

Sample Output

1
0
3

-----------------------------------------------------------------分割线----------------------------------------------------------

题意

略(RT)

思想

扩展中国剩余定理

坑点

1、当excrt返回不为0时,答案即为(maxn-ans)/lcm+1,但excrt返回值为0时,答案为(maxn-ans)/lcm。
2、如果excrt返回值为-1时输出0。
3、我捣鼓了一天。。。一边跑excrt要一边判断ans有没有大于n,如果判断出ans>n了,直接return -1 ! ! !不然会炸LL。因为这个WA了一天的我瑟瑟发抖(这篇博客也是为了纪念一下苦逼的我)。

---------------------------------------------------分割线------------------------------------------------------------------------

#include <bits/stdc++.h>

#define MAXN 15

using namespace std;

typedef long long ll;

ll maxn;
ll lcm;

ll mul(ll a,ll b,ll p)//快乘
{
    a%=p,b%=p;
    if(p<=1e9)
        return a*b%p;
    return (a*b-(ll)(a/(long double)p*b+1e-8)*p+p)%p;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    ll gcd=exgcd(b,a%b,x,y);
    ll tp=x;
    x=y;
    y=tp-a/b*y;
    return gcd;
}

ll excrt(ll mi[],ll ai[],int n)
{
    ll x,y;
    ll M=mi[1],ans=ai[1];
    for(int i=2; i<=n; i++)
    {
        ll a=M,b=mi[i],c=(ai[i]-ans%b+b)%b;
        ll gcd=exgcd(a,b,x,y),bg=b/gcd;
        if(c%gcd!=0)
            return -1;
        x=mul(x,c/gcd,bg);
        ans+=x*M;
        M*=bg;
        ans=(ans%M+M)%M;
        if(ans>maxn)
            return -1;
    }
    lcm=M;
    return (ans%M+M)%M;
}

int main()
{
	ll m,t,i,d,ans;
	ll mi[MAXN],ai[MAXN];
	cin>>t;
	while(t--)
	{
		scanf("%lld%lld",&maxn,&m);
		for(i=1;i<=m;i++)
		{
			scanf("%lld",&mi[i]);
		}
		for(i=1;i<=m;i++)
		{
			scanf("%lld",&ai[i]);
		}
		ans=excrt(mi,ai,m);
		if(ans==-1)
		{
			printf("0\n");
		}
		else
		{
			if(ans==0)
                cout<<(maxn-ans)/lcm<<endl;
            else
                cout<<(maxn-ans)/lcm+1<<endl;
		}
	}
	return 0;
}

忽略我的丑代码,凑合看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值