12 2 2 3
7分析:
1:基本的容斥原理。给定一个N 和一个M集合, 找到小于n 的数中有多少是M中元素的整数倍的 个数。 S= n-1
设xi 为 S 中能被 M 中 i 个数整除的个数 则 Xans = x1 - x2 + x3 -……+(-1)^(m-1)xm。
需要注意的是 , 求能被i 个数整除的 个数的时候, 用(n-1)/ lcm(mi) , 即除以M集合中元素的最小公倍数。
2: 从组合数学上分析
设全集 为 S={1 2 3 , ... , n-1} |s| = n-1;
M = {m1, m2 , ... , mm}, 且 M中 个元素互素
令Qi(i=12, ,,, , m) 表示S中 能被 mi整除的整数这一性质, 令Ai 为S中 具有性质Qi的那些整数所组成的集合。则|A1 υ
A2 υ ...υ Am| 表示S中能被任意mi整除的整数个数。
|S| - |A1 υ A2 υ ...υ Am| 表示 S中 不能被 mi (i = 1, 2 ,...,m) 整除的整数的个数。即S中 与 M 互质的个数。
又 |A1 υ A2 υ ...υ Am| = ∑|Ai| - ∑|Ai ∩ Aj| + ∑|Ai ∩ Aj ∩ Ak| -...+(-1)^(m-1)|A1 ∩ A2 ∩... ∩Am|
又 |Ai| = |S| / (mi) |Ai ∩ Aj| = |S| / (mi * mj) 同理
注意:如果M中各个元素不是 互素的 ,则 |Ai| = |S| / (mi) , |Ai ∩ Aj| = |S| / lcm(mi , mj) ,正是本题题意。
3:容斥原理 ,是采用 dfs 搜索, 分别对 M 中的 每个元素mi 枚举, 然后遍历mi ,搜索树,设树根深度为1, 当树深度为偶数,sum-= , 当 树深度为 奇数时 ,sum+=。
递归图如下:
#include<iostream> #include<cstring> #include<cstdio> #define LL long long using namespace std; int a[30]; int n,m; LL sum; LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } LL lcm(LL a,LL b) { return a/gcd(a,b)*b; } void dfs(int id,int cur,LL lcmx)//id是点的序号,cur是解答树的第几层 { lcmx=lcm(lcmx,a[id]); if(cur%2)//第奇数层 sum+=(n-1)/lcmx; else sum-=(n-1)/lcmx; for(int i=id+1;i<=m-1;i++) dfs(i,cur+1,lcmx); } int main() { while(cin>>n>>m) { int cnt=0; sum=0; for(int i=0;i<=m-1;i++) { int t; cin>>t; if(t) a[cnt++]=t; } m=cnt; for(int i=0;i<=m-1;i++) dfs(i,1,a[i]);//计算m中的每一个数 cout<<sum<<endl; } return 0; }
hdu 4135
题意:就是让你求(a,b)区间于n互质的数的个数.
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define inf 0x3f3f3f3f #define ll long long #include<algorithm> #include<vector> using namespace std; int fac[100010]; ll a,b,n; ll sum; void facx(int n) { int m=sqrt(n+0.5); int x=1; for(int i=2;i<=m;i++) if(n%i==0) { fac[x++]=i; while(n%i==0) n=n/i; } if(n>1) fac[x++]=n; fac[0]=x-1; } ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); } ll lcm(ll a,ll b) { return a/gcd(a,b)*b; } void dfs(int id,int cur,ll lcmx,ll x) { lcmx=lcm(lcmx,fac[id]); if(cur%2==1) sum+=x/lcmx; else sum-=x/lcmx; for(int i=id+1;i<=fac[0];i++) dfs(i,cur+1,lcmx,x); } ll solve(ll x,int n) { sum=0; for(int i=1;i<=fac[0];i++) dfs(i,1,fac[i],x); return sum; } int main() { int t=1; int T; cin>>T; while(T--) { cin>>a>>b>>n; facx(n); ll x=solve(a-1,n); ll y=solve(b,n); cout<<"Case #"<<t++<<": "; cout<<(ll)(b-y-(a-1-x))<<endl; } return 0; }