【codevs3990】中国余数定理2

【题目描述】
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\n0\n");
43     else printf("%lld\n%lld\n",(r-ans)/M+1,ans);
44 }

 

posted @ 2016-11-01 21:25  chty  阅读(244)  评论(0编辑  收藏  举报