POJ2407 Relatives 容斥原理

题意:求1..n-1中与n互质的数的个数(1<=n<=1,000,000,000)。

可以转化为求1..n-1中不与n互质的数的个数t,然后用总数减去就可以了。

对于t的求法,我们可以考虑容斥原理。首先把n质因数分解,然后每个质因数只保留一个,随后按照x与n的公共质因子种类来将x分门别类地计算。例如60=2*2*3*5,那么有2、3、5三种质因子。对于所有符合t的要求的数x,满足是2的倍数的有60/2=30个,满足是3的倍数的有60/3=20个,满足是5的倍数的有60/5=12个。满足同时是2、3的倍数的有60/(2*3)个,满足同时是(2、5)的倍数的有60/(2*5)个……由于重复计算的缘故,我们假设同时满足是p1、p2、...pk的倍数的数的个数为s,那么k为奇数时s对答案的贡献为s,k为偶数时,s对答案的贡献为负。这样对于每一个满足条件的数x,可以证明它在所有分类中的贡献之和恰好为1.这样就算出了所有和n不互质的数的个数了。

#include <cstdio>
#include <cmath>
#define LL long long
#define rep(i,j,k) for (i=j;i<=k;i++) 
using namespace std;
const int N=1e5+5,Pn=30;
int pn,prime[N],notprime[N],fn,fac[Pn];
int n,i;
LL ans;
void Init()
{
	int i,j;
	rep(i,2,N-1)
	{
		if (!notprime[N]) prime[++pn]=i;
		for (j=i+i;j<N;j+=i) notprime[j]=1;
	}
}
void decompose(int n)
{
    fn=0;
	rep(i,1,pn)
	{
		if (prime[i]>(int)trunc(sqrt(n))) break;
		if (n%prime[i]) continue;
		fn++; fac[fn]=prime[i];
	    while (n%prime[i]==0) n/=prime[i];
	}
	if (n>1) fac[++fn]=n;
}
void DFS(int wh,int k,int bsc)
{
	int sgn,_bsc,_k;
	if (wh>fn) return;
	DFS(wh+1,k,bsc);  //不选当前质因子 
	_k=k+1; _bsc=bsc*fac[wh];
	if (_k%2) sgn=1;
	else sgn=-1;
	ans+=sgn*(n/_bsc);
	DFS(wh+1,_k,_bsc);
}
int main()
{
	#ifdef ONLINE_JUDGE
	#else
	      freopen("poj2407.in","r",stdin);
	      freopen("poj2407.out","w",stdout);
	#endif
	Init();
	while (1)
	{
		scanf("%d",&n);
		if (!n) break;
		decompose(n);
	/*	rep(i,1,fn) printf("%d ",fac[i]);
		printf("\n");
	*/	ans=0;
		DFS(1,0,1);
		printf("%d\n",n-ans);
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/Orzage/article/details/78995243