BZOJ-4407: 于神之怒加强版

[文章目录]

Description

多组数据,所有数据的k相同,1<=N,M,K<=5000000,1<=T<=2000 求

推式子!!!

=
=
=
把k*d提前枚举 (注: 的d和k等价于 的p和d/p)
=
诶??辣不是狄利克雷卷积吗?还都是积性函数,直接快筛+分块

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll mod=1000000007ll;
ll k,n,m;
ll ans[5001000],po[5001000];
ll pri[5001000],cnt;
bool v[5001000];
ll pow(ll x,ll y)
{
    ll re=1;
    while(y)
    {
        if(y&1) re=re*x%mod;
        x=x*x%mod; y>>=1;
    }
    return re;
}
void quick_ans()
{
    ans[1]=1; po[1]=1;
    for(ll i=2;i<=5000000;++i)
    {
        if(!v[i])
        {
            pri[++cnt]=i; po[cnt]=pow(i,k);
            ans[i]=(po[cnt]+mod-1)%mod;
        }
        for(ll j=1;i*pri[j]<=5000000&&j<=cnt;++j)
        {
            v[i*pri[j]]=1;
            if(i%pri[j]) ans[i*pri[j]]=ans[i]*ans[pri[j]]%mod;
            else
            {
                ans[i*pri[j]]=ans[i]*po[j]%mod;
                break;
            }
        }
    }
    for(ll i=1;i<=5000000;++i) ans[i]=(ans[i]+ans[i-1])%mod;
}
int main()
{
    int t; scanf("%d%lld",&t,&k);
    quick_ans();
    while(t--)
    {
        scanf("%lld%lld",&n,&m); if(n>m) swap(n,m);
        ll b=1,e,fna=0;
        while(b<=n)
        {
            e=min(n/(n/b),m/(m/b));
            fna=(fna+(ans[e]-ans[b-1]+mod)%mod*(n/b)%mod*(m/b)%mod)%mod;
            b=e+1;
        }
        printf("%lld\n",fna);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注