题目传送门:点击打开链接
题意:给你区间[a,b],在这区间里 找出 既是7的倍数 x,并且 x%pi!=ai的个数 有多少?
思路:看到这题 跟模有关系 大概跟 中国剩余定理有关,可是题目说的 只要 符合 x%pi=ai一项 就不能算个数,所以只是中国剩余定理 不可行的,那么我们只有一个一个 求出个数,然后再用7的倍数的个数-求出的个数,可是 一个一个求这会有重复的,所以我们 就要用到容斥。。 如果在容斥的过程中用普通互素的中国剩余定理的方法 那就要注意在解的时候会出现 爆long long的情况,当然 我们也可以避免这种情况,第一种用快速乘法。那么 第二种方法可以正常解,并且不会爆long long .
第二种:解释: 我们在第一种的方法 是 列 方程 x=ai mod pi,再运用中国剩余定理,而我们现在 利用7的倍数这个条件 列出 7x= ai mod pi 然后对他化简 x= ci mod pi 注意这里的x 符合条件 a<=7x<=b 即 在[a,b]符合 7的倍数 可以写成 7*p,7*(p+1),7*(p+2),7*(p+3).......,那么这里的x=p,p+1,p+2,p+3.... 所以区间我们可以变成 [a/7,b/7] 所以接下来的思路和第一种一样 运用容斥和普通的互素的中国剩余定理 就可以解决 这个爆long long 的问题。(其实 就是 M比第一种的M少乘个7)
当然 如果你用不互素的中国剩余定理的模版 应该也不会出现 long long 的问题。在这里那代码我就只是贴 普通互素中国剩余定理 的二种情况的代码了,最后一个就不贴了。
第二种:
#include <iostream>
#include <cstring>
#define rep(i,o,u) for(int i=(int)(o);i<=(int)(u);++i)
#define clr(a,x) memset(a,(x),sizeof(a))
using namespace std;
typedef long long ll;
ll n,x,y;
ll a[20],b[20];int cnt=0;
void ex_gcd(ll aa,ll bb,ll &xx,ll &yy)
{
if(!bb)
{
xx=1,yy=0;
return;
}
ll x1,y1;
ex_gcd(bb,aa%bb,x1,y1);
xx=y1,yy=x1-(aa/bb)*y1;
}
void solve()
{
cin>>n>>x>>y;
rep(i,0,n-1)
{
cin>>a[i]>>b[i];
for(ll j=0;;++j) //化简 式子
if((b[i]+j*a[i])%7==0)
{
b[i]=((b[i]+j*a[i])/7)%a[i];
break;
}
}
int e=1<<n;ll ans=0;
rep(i,1,e-1)
{
int nn=0;ll M=1,aa=0;
int data[16];
rep(j,0,n-1)
{
if((1<<j)>i)
break;
if((1<<j)&i)
{
data[nn++]=j;
M*=a[j];
}
}
rep(j,0,nn-1)
{
ll xx,yy,m=M/a[data[j]];
ex_gcd(m,a[data[j]],xx,yy);
aa=((aa+((xx*m)%M)*b[data[j]])%M+M)%M;
}
ll tt=0;
tt+=(y/7-aa)/M;
tt-=((x-1)/7-aa)/M;
if(aa>(x-1)/7&&aa<=y/7)
++tt;
if(nn&1)
ans+=tt;
else
ans-=tt;
}
ans=(y/7-(x-1)/7)-ans;
cout<<"Case #"<<++cnt<<": ";
cout<<ans<<endl;
}
int main(int argc, const char * argv[])
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
第一种:
#include <iostream>
#include <cmath>
#define rep(i,o,u) for(int i=o;i<=u;++i)
using namespace std;
typedef long long ll;
ll pi[16],ai[16];
ll x,y;int cnt=0;
void ex_gcd(ll a,ll b,ll &xx,ll &yy)
{
if(!b)
{
xx=1,yy=0;
return;
}
ll x1,y1;
ex_gcd(b,a%b,x1,y1);
xx=y1,yy=x1-(a/b)*y1;
}
ll quickmul(ll a,ll b,ll mod)
{
ll ans=0;
a%=mod;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
b>>=1;
a=(a+a)%mod;
}
return ans;
}
void solve()
{
ll ans=0;
int n;ll M;
cin>>n>>x>>y;
pi[n]=7,ai[n]=0;
ans=y/7-(x-1)/7;
rep(i,0,n-1)
cin>>pi[i]>>ai[i];
int e=1<<(n);
rep(i,1,e-1)
{
M=1;int nn=0;
ll data[16];
ll xx=1,yy=1;
rep(j,0,n)
{
if((1<<j)>i)
break;
if((1<<j)&i)
{
data[nn++]=j;
M*=pi[j];
}
}
data[nn++]=n;
M*=7;
ll aa=0;
rep(j,0,nn-1)
{
ll m=M/pi[data[j]];
ex_gcd(m,pi[data[j]],xx,yy);
aa=(aa+quickmul(quickmul(xx,m,M),ai[data[j]],M))%M;
}
if(aa<0)
aa+=M;
ll t=0;
t=(y-aa)/M-(x-aa-1)/M;
if(aa>=x&&aa<=y)
++t;
if(nn&1)
ans+=t;
else
ans-=t;
// cout<<aa<<" "<<M<<": ";
// cout<<t<<endl;
}
cout<<"Case #"<<++cnt<<": "<<ans<<endl;
}
int main(int argc, const char * argv[])
{
int t;
cin>>t;
while(t--)
{
solve();
}
return 0;
}