【题目描述】
Skytree神犇最近在研究中国博大精深的数学。
这时,Sci蒟蒻前来拜访,于是Skytree给Sci蒟蒻出了一道数学题:
给定n个质数,以及k模这些质数的余数。问:在闭区间[a,b]中,有多少个k?最小的k是多少?
Sci蒟蒻数学能力差了Skytree三条街,所以他只好寻求计算机的帮助。他发邮件给同为oier的你,你能帮他解决这个问题吗?
【题解】
用中国剩余定理求出最小的k,然后k+M*y都是可能的值,所以个数就是(b-k)/M+1
注意在统计答案时,由于模数M可能过大,要使用快速乘。
1 /************* 2 CODEVS 3990 3 by chty 4 2016.11.1 5 *************/ 6 #include<iostream> 7 #include<cstdio> 8 #include<cstring> 9 #include<cstdlib> 10 #include<cmath> 11 #include<ctime> 12 #include<algorithm> 13 using namespace std; 14 typedef long long ll; 15 ll n,l,r,ans,M(1),a[15],m[15]; 16 inline ll read() 17 { 18 ll x=0,f=1; char ch=getchar(); 19 while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();} 20 while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 21 return x*f; 22 } 23 void exgcd(ll a,ll b,ll &x,ll &y) 24 { 25 if(b==0) {x=1; y=0; return;} 26 exgcd(b,a%b,x,y); 27 ll t=x;x=y;y=t-a/b*y; 28 } 29 ll mul(ll x,ll y){return ((x*y-(ll)(((long double)x*y+0.5)/M)*M)%M+M)%M;}//一行快速乘 30 int main() 31 { 32 freopen("cin.in","r",stdin); 33 freopen("cout.out","w",stdout); 34 n=read(); l=read(); r=read(); 35 for(ll i=1;i<=n;i++) m[i]=read(),a[i]=read(),M*=m[i]; 36 for(ll i=1;i<=n;i++) 37 { 38 ll x,y,Mi=M/m[i]; 39 exgcd(Mi,m[i],x,y); 40 ans=(ans+mul(mul(x,Mi),a[i]))%M; 41 } 42 if(ans<l||ans>r) printf("0 0 "); 43 else printf("%lld %lld ",(r-ans)/M+1,ans); 44 }