题意:求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;
}