upc数学一本通【数论】X问题(线性同余方程求正整数解的个数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winter2121/article/details/81975927

问题 T: 【数论】X问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 5  解决: 3
[提交] [状态] [讨论版] [命题人:admin]

题目描述

求在小于等于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)。

输入

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

输出

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

样例输入

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

样例输出

1
0
3

[提交][状态]

【分析】

根据题意,很明显的线性同余方程组。

结合拓展欧几里得可以解得最小特解px,然后分情况计算一下n之内的特解个数即可。

线性同余方程:https://blog.csdn.net/winter2121/article/details/71123565

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

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

int getpx(int x[],int y[],int top)
{
    int a=x[0],b=y[0],k1,k2;
    for(int i=1;i<top;i++)
    {
        int r=y[i]-b;
        int d=exgcd(a,x[i],k1,k2);
        ll lcm=1ll*a/d*x[i];
        if(r%d)return -1; //无解
        int t=x[i]/d;
        k1=(k1*r/d%t+t)%t;

        b=k1*a+b;
        a=lcm;
        b%=a;
    }
    return b;
}

int solve()
{
    int n,m,a[12],b[12];
    int x[12],y[12];
    scanf("%d%d",&n,&m);
    ll lcm=1;
    for(int i=0;i<m;i++)scanf("%d",&a[i]),lcm=lcm*a[i]/gcd(lcm,a[i]);
    for(int i=0;i<m;i++)scanf("%d",&b[i]);
    ll px=getpx(a,b,m);
    ll ans=0;
    if(px==0)ans=n/lcm;
    else if(px==-1)ans=0;
    else if(n>=px)ans=(n-px)/lcm+1;
    else ans=0;
    printf("%lld\n",ans);
}
int main()
{
    int T;
    for(cin>>T;T--;)solve();
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/81975927