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


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值