hdu_5768_Lucky7(中国剩余定理+容斥)

题目链接: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
",ic++,ans);
55     }
56     return 0;
57 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/5721157.html