1. 程式人生 > >spoj 4168. Square-free integers(容斥)

spoj 4168. Square-free integers(容斥)

求出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;
}