容斥原理:;
容斥原理的实现:
用一个temps[maxn]数组记录各个容斥加减,用-1的连乘进行哈,用a[maxn]数组记录元素的个数;
然后具体的实现算法代码如下:复杂度为O(2^n)
int temp[maxn];
int cnt = 0;
temp[cnt ++] = -1;
for(int i = 0;i < cnt1 ; i ++)//容斥记录所有的情况//cnt1是a[]的大小
{
int k = cnt;
for(int j = 0; j < k ; j ++)
{
temp[cnt ++] = temp[j] * a[i] * (- 1);
}
}
ll ans = 0;
for(int i = 1; i < cnt ; i ++)
ans += temp[i];
return ans;
题意:求在区间[ x , y ]有多少数与n 互质;
思路:将n拆分成质因数,然后在[x,,y]这个区间的找到能被这些质因数整除的数,用在这个区间的数的个数减去能被这些质因数整除的数的个数。
因为各个素数对应的数有可能重合,所以这里就要用到容斥原理;
可以先求【1,y】,【1,x - 1】对应的个数,之后前者减去后者;因为这里考虑到了个数,容斥进行的是他们对应的公倍数,然后用区间长度除一下这个公倍数就对应的是对应的个数了;
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000+ 10;
typedef long long ll;
int a[maxn];//记录的是n的质因子
ll temp[maxn*10];//记录的容斥的元素
int Init(ll n)//得出n的质因子数组
{
int num = 0;
for(int i = 2; i * i <= n ; i ++)
{
if(n % i == 0)
{
a[num ++] = i;
while(n % i == 0)
{
n = n / i;
}
}
}
if(n > 1)//剩下的是质数了
{
a[num ++] = n;
}
return num;
}
ll Eclusion(ll m,ll n)
{
memset(a,0,sizeof(a));
memset(temp,0,sizeof(temp));
int num = Init(n);
int len = 0;
temp[len ++] = -1;
for(int i = 0;i < num ; i ++)//容斥记录所有的情况
{
int k = len;
for(int j = 0; j < k ; j ++)
{
temp[len ++] = temp[j] * a[i] * (- 1);
}
}//temp数组记录的容斥后的各个带符号的公倍数
ll ans = 0;
for(int i = 1; i < len ; i ++)
{
ans += m/temp[i];
}
return ans;//ans记录的是不符合与n互质的数的个数
}
int main()
{
int Tcase;
scanf("%d",&Tcase);
for(int ii = 1; ii <= Tcase ; ii ++)
{
ll x,y,n;
scanf("%I64d%I64d%I64d",&x,&y,&n);
ll ans = (y - Eclusion(y,n)) - (x - 1 - Eclusion(x - 1,n));
cout <<"Case #"<< ii << ": "<< ans << endl;
}
return 0;
}