感觉断断续续的看了好久的容斥……然后还是看不懂莫比乌斯反演……以后基本原理懂了就先上手做题吧,不然感觉还是不会还浪费时间…………
第一题容斥…………
题意:给你一个数n[1,10^18],叫你求n内有多少个数是m^k得来的。
可知:m^k都可以变成一个幂数为素数的形式,所以可以枚举素数,求每个素数满足的个数。因为存在 形如 x^3=y^5 ,的重叠部分,所以这里用容斥原理,因为2^60>10^18,且2*3*5*7>60,则只需要枚举三个数内的容斥即可。
注意处理精度的小tip
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define ll __int64
using namespace std;
ll prime[65],que[50];
#define eps 1e-12
ll top;
void getprime()
{
ll i,j,k;
memset(prime,1,sizeof(prime));
prime[0]=prime[1]=0;
for(i=2;i<65;i++)
{
if(prime[i])
for(j=i+i;j<65;j+=i)
prime[j]=0;
}
for(i=2;i<65;i++)
if(prime[i]) que[top++]=i;
}
int main()
{
ll n;
top=0;
getprime();
while(scanf("%I64d",&n)!=EOF)
{
ll i,j,k;
ll tmp;
ll ans=1;
for(i=0;i<top;i++)
{
tmp=(ll)pow((double)n,1.0/que[i]+eps);
if(tmp==1) break;
ans+=(tmp-1);
}
for(i=0;i<top;i++)
{
for(j=i+1;j<top;j++)
{
tmp=(ll)pow((double)n,1.0/(que[i]*que[j])+eps); //这里的eps处理精度一定要注意
if(tmp==1) break;
ans-=(tmp-1);
}
}
for(i=0;i<top;i++)
{
for(j=i+1;j<top;j++)
{
for(k=j+1;k<top;k++)
{
tmp=(ll)pow((double)n,1.0/(que[i]*que[j]*que[k])+eps);
if(tmp==1) break;
ans+=(tmp-1);
}
}
}
printf("%I64d\n",ans);
}
return 0;
}