bzoj4407: 于神之怒加强版

懵逼乌斯反演裸题

画完柿子只要预处理S(i)=sigema(d|i)d u(i/d)*d^k

线性筛它一手

i%prime[j]!=0的话,首先i的因子也是i*prime[j]的因子,但是由于多了一个质因子所以正负性反过来。其次多了这个prime[j],i的所有因子都可以乘这个数,同样是它的因子,值的变化就是prime[j]^k。合起来S[i*prime[j]]=-S[i]+S[i]*prime[j]^k,结果亮老师一眼秒了S这个东西是一个积性函数,我一脸懵逼。。。想一想当是质数的时候,好像S值就是prime^k-1。。。然后百度一手发现这个是狄利克雷卷积的形式。。。好的扔了

i%prime[j]==0,我们换种表示方法,设i=x*p^q,对于S[i],有贡献的d,只能具有q或q-1个p,而对于i*prime[j]也就是x*p^(q+1)来说,有贡献的d是具有q+1或q个p的。而贡献,是d^k。那么前面的q对应后面的q+1,前面的q-1对应后面的q,要乘上的就是prime[j]^k

没取模好还挂了一次。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int mod=1e9+7;

int K;
int quick_pow(int A)
{
    int ret=1;int p=K;
    while(p!=0)
    {
        if(p%2==1)ret=(LL)ret*A%mod;
        A=(LL)A*A%mod;p/=2;
    }
    return ret;
}
int pr,prime[5000010],u[5000010],mi[5000010],S[5000010];
bool v[5000010];
void get_prime()
{
    pr=0;u[1]=1;mi[1]=1;S[1]=1;
    for(int i=2;i<=5000000;i++)
    {
        mi[i]=quick_pow(i);
        if(v[i]==false)
        {
            u[i]=-1,S[i]=(mi[i]-1+mod)%mod;
            prime[++pr]=i;
        }
        for(int j=1;j<=pr&&i*prime[j]<=5000000;j++)
        {
            v[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                u[i*prime[j]]=0,S[i*prime[j]]=(LL)S[i]*mi[prime[j]]%mod;
                break;
            }
            else u[i*prime[j]]=-u[i],S[i*prime[j]]=(LL)S[i]*S[prime[j]]%mod;
        }
    }
    for(int i=2;i<=5000000;i++)S[i]=(S[i]+S[i-1])%mod;
}

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int T;
    scanf("%d%d",&T,&K);get_prime();
    while(T--)
    {
        int n,m,last,ans=0;
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);
        for(int i=1;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            ans=((LL)ans+(LL)(m/i)*(LL)(n/i)%mod*(LL)(S[last]-S[i-1]+mod)%mod)%mod;
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/9870049.html