容斥原理

容斥原理

HDU 4135

Problem Description

Input

Output

Sample Input

Sample Output

题目要求

找出区间[a,b]内与n互质的个数

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include <cstring>
#define LL long long
using namespace std;
LL ans;
int a[1000];
int num;
void get_prime(LL n) //快速求出所有n的质因子
{ //使用唯一分解定理 任何一个数都可以拆分成若干个质数的乘积
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
a[num++]=i;
while(n%i==0)
n/=i;
}
}
if(n>1) //注意最后一项的处理
a[num++]=n;
}
LL rongchi(LL m) //容斥原理公式
{
LL que[10000];
LL sum=0;
int t=0;
que[t++]=-1;
for(int i=0;i<num;i++)
{
int k=t;
for(int j=0;j<k;j++)
que[t++]=(-1)*a[i]*que[j];
}
for(int i=1;i<t;i++)
sum+=m/que[i];
return sum;
}
int main()
{
/*freopen("input.txt","r",stdin);*/
int t;
scanf("%d",&t);
int flag=1;
while(t--)
{
LL x,y;
int n;
scanf("%lld%lld%d",&x,&y,&n);
memset(a,0,sizeof(a));
ans=0,num=0;
get_prime(n);
ans=(y-rongchi(y))-(x-1-rongchi(x-1));
printf("Case #%d: %lld\n",flag++,ans);
}
return 0;
}

思路

我们可以先转化下:用(1,b)区间与n互质的数的个数减去(1,a-1)区间与n互质的数的个数,那么现在就转化成求(1,m)区间于n互质的数的个数,如果要求的是(1,n)区间
与n互质的数的个数的话,我们直接求出n的欧拉函数值即可,可是这里是行不通的!我们不妨换一种思路:就是求出(1,m)区间与n不互质的数的个数,假设为num,
那么我们的答案就是:m-num!现在的关键就是:怎样用一种最快的方法求出(1,m)区间与n不互质的数的个数?方法实现:我们先求出n的质因子(因为任何一个数都可以
分解成若干个质数相乘的),如何尽快地求出n的质因子呢?使用代码给出的方法
举一组实例吧:假设m=12,n=30.
第一步:求出n的质因子:2,3,5;
第二步:(1,m)中是n的因子的倍数当然就不互质了(2,4,6,8,10)->n/2 6个,(3,6,9,12)->n/3 4个,(5,10)->n/5 2个。
如果是粗心的同学就把它们全部加起来就是:6+4+2=12个了,那你就大错特错了,里面明显出现了重复的,我们现在要处理的就是如何去掉那些重复的了
第三步:这里就需要用到容斥原理了,公式就是:n/2+n/3+n/5-n/(2×3)-n/(2×5)-n/(3×5)+n/(2×3×5).
第四步:我们该如何实现呢?我在网上看到有几种实现方法:dfs(深搜),队列数组,位运算三种方法都可以 上述公式有一个特点:n除以奇数个数相乘的时候是加,
n除以偶数个数相乘的时候是减(奇加偶减)。这里用队列数组实现:我们可以把第一个元素设为-1 具体看代码实现

HDU 1796

Problem Description

Input

Output

Sample Input

Sample Output

题目要求

给出N和一个数集 求1—N中可以被数集中的任何元素整除的所有数的个数

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <cstring>
#include <iostream>
#define LL long long
using namespace std;
LL n,ans;
int m,cnt;
int a[15];
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
void dfs(int cur,LL lcm,int id)
{
lcm=a[cur]/gcd(a[cur],lcm)*lcm;
if(id&1)
ans+=(n-1)/lcm;
else
ans-=(n-1)/lcm;
for(int i=cur+1;i<cnt;i++)
dfs(i,lcm,id+1);
}
int main()
{
/*freopen("input.txt","r",stdin);*/
while(scanf("%lld%d",&n,&m)!=EOF)
{
cnt=0,ans=0;
memset(a,0,sizeof(a));
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
if(x!=0) //x为非负数 需要把0排除
a[cnt++]=x;
}
for(int i=0;i<cnt;i++)
dfs(i,a[i],1);
printf("%lld\n",ans);
}
return 0;
}

思路

容斥原理地简单应用。先找出1…n内能被集合中任意一个元素整除的个数,再减去能被集合中任意两个整除的个数,即能被它们两只的最小公倍数整除的个数,
因为这部分被计算了两次,然后又加上三个时候的个数,然后又减去四个时候的倍数…所以深搜,最后判断下集合元素的个数为奇还是偶,奇加偶减。

HDU 2841

Problem Description

Input

Output

Sample Input

Sample Output

题目要求

从(1,1)开始的N×M的格子上有树,从(0,0)点可以看到多少棵树

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include<cstdio>
#include<vector>
#define maxn 100050
#define LL long long
using namespace std;
vector<int>e[maxn];
int que[maxn];
void init()
{
for(int i=0;i<maxn;i++)
e[i].clear();
for(int i=2;i<maxn;i++)
{
int t=i;
for(int j=2;j*j<maxn;j++)
{
if(t%j==0)
{
e[i].push_back(j);
while(t%j==0)
t/=j;
}
}
if(t>1)
e[i].push_back(t);
}
}
LL rongchi(int n,int s)
{
int num=0;
que[num++]=1;
for(int i=0;i<e[s].size();i++)
{
int ep=e[s][i];
if(ep>n)
break;
int k=num;
for(int j=0;j<k;j++)
que[num++]=que[j]*(-1)*ep;
}
LL sum=0;
for(int i=0;i<num;i++)
sum+=n/que[i];
return sum;
}
int main()
{
/*freopen("input.txt","r",stdin);*/
init();
int t;
scanf("%d",&t);
while(t--)
{
int m,n;
scanf("%d%d",&m,&n);
LL ans=n;
for(int i=2;i<=m;i++)
ans+=rongchi(n,i);
printf("%lld\n",ans);
}
return 0;
}

思路

因为ans初始化为n 所以从第二行开始为奇减偶加
经画图推敲可以发现如果A1/B1=A2/B2那么就有一棵树看不到,所以就是找出Ai/Bi有多少种。
再可以发现A/B中,如果A,B有大于1的公约数,则A=A’×D B=B’×D,那么A/B=A’/B’,也就是存在另外一组数和这种相等,则问题转换成有多少对互质的数。
本题和HDU 4135唯一的区别就是枚举i,从1-M中找与i互质的数,其中1<=i<=N。
容注意先预处理i的所有素因子,然后容斥就可以了。

文章目录
  1. 1. 容斥原理
    1. 1.1. HDU 4135
      1. 1.1.1. 题目要求
      2. 1.1.2. 参考AC代码
      3. 1.1.3. 思路
    2. 1.2. HDU 1796
      1. 1.2.1. 题目要求
      2. 1.2.2. 参考AC代码
      3. 1.2.3. 思路
    3. 1.3. HDU 2841
      1. 1.3.1. 题目要求
      2. 1.3.2. 参考AC代码
      3. 1.3.3. 思路
|