标签:
题目链接:hdu_5768_Lucky7
题意:
给你一个区间,问你这个区间内是7的倍数,并且满足%a[i]不等于w[i]的数的个数
乍一看以为是数位DP,仔细看看条件,发现要用中国剩余定理,然后容斥一下就出答案了,不过这里在中国剩余定理里面的乘法会有数据爆long long ,所有要写一个高精度乘法,这里卡死很多人、
1 #include <bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 typedef long long ll; 5 6 ll a[20],w[20],l,r; 7 int t,n,vis[20],ic=1; 8 9 ll mut(ll a,ll b,ll mod)//高精度求乘法 10 { 11 ll an=0; 12 while(b){if(b&1)an=(an+a)%mod;b>>=1,a=(a<<1)%mod;} 13 return an; 14 } 15 16 ll Extended_Euclid(ll a, ll b, ll &x, ll &y)//扩展欧几里得算法 17 { 18 if(b==0){x=1,y=0;return a;} 19 ll d=Extended_Euclid(b,a%b,y,x); 20 y-=a/b*x; 21 return d; 22 } 23 24 inline ll cal(ll r,ll l,ll m){return (r-l)/m;} 25 26 ll Chinese_Remainder(int len=n+1)//中国剩余定理,a[]存放余数,w[]存放两两互质的数 27 { 28 ll x,y,m,N=1,ret=0; 29 F(i,1,len)if(vis[i])N*=w[i];//从1开始 30 F(i,1,len)if(vis[i])m=N/w[i],Extended_Euclid(w[i],m,x,y), 31 ret=(ret+mut(mut(y,m,N),a[i],N))%N;//注意是否爆ll 32 ret=(N+ret%N)%N; 33 return cal(r+N,ret,N)-cal(l-1+N,ret,N); 34 } 35 36 int main() 37 { 38 scanf("%d",&t); 39 w[1]=7,a[1]=0,vis[1]=1; 40 while(t--) 41 { 42 scanf("%d%lld%lld",&n,&l,&r); 43 F(i,2,n+1)scanf("%d%d",w+i,a+i); 44 F(i,2,n+1)vis[i]=0; 45 ll ans=0; 46 int end=1<<n; 47 for(int i=0;i<end;i++) 48 { 49 int tp=i,cnt=0; 50 F(j,2,n+1)vis[j]=tp&1,tp>>=1,cnt+=vis[j]; 51 cnt=cnt&1?-1:1; 52 ans+=1ll*cnt*Chinese_Remainder(); 53 } 54 printf("Case #%d: %lld\n",ic++,ans); 55 } 56 return 0; 57 }
标签:
原文地址:http://www.cnblogs.com/bin-gege/p/5721157.html