hdu1573 (中国剩余定理+扩展欧几里得)

题干:求在小于等于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)。中文题。

题目思路:裸的中国剩余定理,可以练练手。

先从两个式子入手:x+a[0]*k1=b[0];

                              x+a[1]*k2=b[1];    由以上两式子可以得出:a[1]*k2-a[0]*k1=b[1]-b[0];

用扩展欧几里得可以解出上述式子,之后类推即可。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#define Memset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1010;
#define LL long long
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
LL ex_gcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    LL ans=ex_gcd(b,a%b,x,y);
    LL tmp=x;
    x=y;
    y=tmp-a/b*y;
    return ans;
}
LL modeqset(LL a[],LL b[],LL n)
{
    LL i,d,c,x,y,t;
    for(i=1;i<n;i++)
    {
        c=b[i]-b[i-1];
        d=ex_gcd(a[i-1],a[i],x,y);
        if(c%d) return -1;
        t=a[i]/d;
        x=(x*(c/d)%t+t)%t;    //解决x的负数情况,因为x+kt是式子的解,所以((x+kt)%t+t)%t)也必定是式子的正数解;
        b[i]=x*a[i-1]+b[i-1];
        a[i]=a[i-1]*(a[i]/d);  //以前面的解推出后面系数,依此类推。
    }
    return b[n-1];
}
int main()
{
    LL a[30],b[30],m,tmp,flag,i,n,lcm=1,num;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        lcm=1;
        scanf("%lld%lld",&n,&m);
        for(i=0;i<m;i++)
        {
            scanf("%lld",&a[i]);
            lcm=lcm/(gcd(lcm,a[i]))*a[i];    //求出a[i]的最大公倍数;
        }
        for(i=0;i<m;i++)
            scanf("%lld",&b[i]);
        LL res=modeqset(a,b,m);
        if(res==-1|| res>n)
            printf("0\n");
        else
        {
            num=(n-res)/lcm+1;              //n和解的最小值相减,之后除以最大公倍数,加上原本的res;
            if(res==0)        
                num--;                      //若res=0,就多加了1,减去即可。
            printf("%lld\n",num);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ygl_6saltfish/article/details/80021035