spoj 4168. Square-free integers(容斥)

http://www.spoj.com/problems/SQFREE/


求出1~n(n <= 10^14)内不被任意一个完全平方数整除的数的个数。


同样的,考虑问题的逆问题,就是至少能被一个完全平方数整除的数的个数。所以答案就是 n - ( 1~n内完全平方数的倍数的个数 )。


所以可以枚举i( 2 <= i <= sqrt(n) ),i*i是一个完全平方数,那么能被i*i整除的数的个数为 n / (i*i)。显然里面有重复的,例如4,9,和36,

36就被多计算的一次,所以减掉,就是容斥。 和上题类似,看i的质因子数是奇数还是偶数,是奇数就加上,偶数就减掉,注意i的质因子不能有重复的。


每个数的质因子个数我们可以提前dfs预处理出来。


#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
//#define LL __int64
//#define LL long long
#define eps 1e-9
#define PI acos(-1.0)
typedef long long LL;
using namespace std;

const int maxn = 10000010;
int cnt[maxn];
bool flag[maxn];
int prime[maxn];
int p_num;

void getPrime()
{
	int m = sqrt(maxn);
	memset(flag,false,sizeof(flag));
	p_num = 0;
	for(int i = 2; i <= m; i++)
	{
		if(flag[i] == false)
		{
			for(int j = i+i; j <= maxn; j += i)
				flag[j] = true;
		}
	}
	for(int i = 2; i < maxn; i++)
		if(flag[i] == false)
			prime[p_num++] = i;
}


void dfs(int st, LL s, int num)
{
	cnt[s] = num&1 ? 1 : -1;
	for(int i = st; i < p_num; i++)
	{
		LL tmp = prime[i] * s;
		if(tmp > maxn)
			break;
		dfs(i+1,tmp,num+1);
	}
}

int main()
{
	int test;
	memset(cnt,0,sizeof(cnt));
	getPrime();
	dfs(0,1LL,0);
	scanf("%d",&test);
	while(test--)
	{
		LL n;
		scanf("%lld",&n);
		int m = sqrt(n+0.5);
		LL ans = 0;
		for(int i = 2; i <= m; i++)
		{
			if(cnt[i])
			{
				ans += cnt[i]*n/((LL)i*i);
			}
		}
		ans = n - ans;
		printf("%lld\n",ans);
	}
	return 0;
}



你可能感兴趣的:(容斥原理)