【中国剩余定理-求X解的个数】HDU 1573 X问题

X问题

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4343    Accepted Submission(s): 1390


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
 

Author
lwg
 

Source
HDU 2007-1 Programming Contest
 

题意:

计算小于N的数,有多少符合给定的同余方程组。

解题思路:

利用中国剩余定理,主要求出最小的值,然后注意枚举的方法。

AC代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

LL gcd(LL a,LL b)
{
    if(!b)
        return a;
    return gcd(b,a%b);
}

LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b){
        x=1;y=0;
        return a;
    }
    LL r=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-(a/b)*y;
    return r;
}

LL mod_reverse(LL A,LL B)
{
    LL x,y;
    LL r=exgcd(A,B,x,y);
    if(r==1) return (x%B+B)%B;
    return -1;
}

LL Merge(LL &A,LL B,LL &mod_A,LL mod_B)
{
    LL C=gcd(mod_A,mod_B);
    LL d=B-A;
    if(d%C) return -1;
    LL MOD=(mod_A/C*mod_B);
    d=((d/C)%MOD+MOD)%MOD;
    LL A1=mod_reverse(mod_A/C,mod_B/C);
    LL K=A1*d;
    A=mod_A*K+A;
    mod_A=MOD;
}

LL CRT(LL *A,LL *M,int N)
{
    LL res=M[0];
    for(int i=1;i<N;i++){
        if(Merge(A[0],A[i],M[0],M[i])==-1) return -1;
    }
    if(A[0]==0) return M[0];
    LL x,y;
    LL a=1;
    LL r=exgcd(a,M[0],x,y);
    if(r==1) return ((x*A[0])%M[0]+M[0])%M[0];
    return -1;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        LL A[15],M[15];
        LL S;
        int N;
        scanf("%lld%d",&S,&N);
        for(int i=0;i<N;i++)
            scanf("%lld",&M[i]);
        for(int i=0;i<N;i++)
            scanf("%lld",&A[i]);
        LL ans=CRT(A,M,N);
        if(ans==-1||ans>S) printf("0\n");
        else{
            int n=0;
            while(ans+M[0]*n<=S){ //一个一个枚举会超时。
                n++;
            }
			printf("%d\n",n);
		}
    }
    return 0;
}




你可能感兴趣的:(【中国剩余定理-求X解的个数】HDU 1573 X问题)