版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzj1054689699/article/details/81104644
Description
Solution
定义i的指数为 ,满足 且
如果对于一个 ,存在一个数 ,使得 ,那么我们可以将它们合在一起做,因为只有这样它们的幂才有公共部分
容易发现
在
以内最多为29,并且当
时
都是1
那么我们将大于
的部分去掉被合在一起做的数以后,剩下都是互不干扰的,可以直接乘以B
直接最后再加上
现在的问题变成已知
,
,求
有多少种不同的取值
取以i为底的对数,那就是求
有多少种不同的取值,并且这个问题与具体的i无关,只与c有关
考虑将原来问题分成若干段处理,第k段为 ,我们想知道这段中有多少数是 中某个数的倍数,这样有效排除了干扰
这个问题可以容斥解决,但是 数最多有29个,直接容斥时间会有问题,然而发现如果之中一个数是另一个数的倍数,那这个大的数显然没用,这样只有15个左右,可以通过本题。
注意由于这里面的数不一定互质,因此容斥要取最小公倍数而不是直接相乘。
Code
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 40005
using namespace std;
LL n,m,cnt,f[31],g[31],sp,pr[11]={0,2,3,5,7,11,13,17,19,23,29},gd[31][31];
bool bz[N];
int cn[31],mu[31],d[31];
LL gcd(LL x,LL y)
{
return(y)?gcd(y,x%y):x;
}
void dfs(int l,LL s,LL v,LL x,LL y)
{
if(s>y) return;
sp+=v*(y/s-(x-1)/s);
fo(k,l,d[0]) dfs(k+1,s*(LL)d[k]/gcd(s,d[k]),-v,x,y);
}
int main()
{
cin>>n>>m;
mu[1]=1;
LL n1=sqrt(n),ans=1,cnt=n-n1;
f[1]=m;
fo(c,2,30)
{
f[c]=m;
fo(i,2,c)
{
d[0]=0;
fo(j,i,c)
{
bool pd=1;
fo(k,i,j-1) if(j%k==0) {pd=0;break;}
if(pd) d[++d[0]]=j;
}
sp=0;
fo(j,1,d[0]) dfs(j+1,d[j],1,(LL)(i-1)*m+1,(LL)i*m);
f[c]+=sp;
}
}
fo(i,2,n1)
{
if(!bz[i])
{
LL v=i;
LL c=0;
while(v<=n)
{
c++;
if(v<=n1) bz[v]=1;
else cnt--;
v=v*(LL)i;
}
ans+=f[c];
}
}
ans+=cnt*m;
printf("%lld\n",ans);
}