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
解题思路:计算小于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; }