【数论】【容斥】[JZOJ4392] 幂

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hzj1054689699/article/details/81104644

Description

这里写图片描述
这里写图片描述

Solution

定义i的指数为 c i ,满足 i c i A i c i + 1 > A

如果对于一个 i ,存在一个数 j ,使得 j p = i , p c i , p N + ,那么我们可以将它们合在一起做,因为只有这样它们的幂才有公共部分

容易发现 c i 10 9 以内最多为29,并且当 i > n c i 都是1
那么我们将大于 n 的部分去掉被合在一起做的数以后,剩下都是互不干扰的,可以直接乘以B

i = 1 直接最后再加上
现在的问题变成已知 i , q [ 1 , c i ] , Y [ 1 , B ] ,求 ( i q ) Y 有多少种不同的取值
取以i为底的对数,那就是求 q [ 1 , c i ] , Y [ 1 , B ] q × Y 有多少种不同的取值,并且这个问题与具体的i无关,只与c有关

考虑将原来问题分成若干段处理,第k段为 [ ( k 1 ) × B + 1 , k × B ] ,我们想知道这段中有多少数是 [ k , c i ] 中某个数的倍数,这样有效排除了干扰

这个问题可以容斥解决,但是 [ k , c i ] 数最多有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);
}

猜你喜欢

转载自blog.csdn.net/hzj1054689699/article/details/81104644