于神之怒加强版P4449 BZOJ4407

           通过这道题,我才知道 积性函数 可以通过 线性筛 来筛。

           题目就是就是一道 莫比乌斯 模板题的加强 

           原来那倒题是ΣΣgcd(i, j)   现在变成了 ΣΣ(gcd(i,j)^k % mod)

           令x = gcd(i, j)   f(x) = x ^ k;

           原式: ΣΣf(x)

           令 f = g (卷积) 1

           则g = f (卷积) u

           推出    g(x) = \sum_{d | x}{f(d) * u(d / x)}             

           --------------------------------------------------------------------------------

           以前我是通过 暴力枚举 d 然后再 枚举 x = d * i  来先求出g(x)

           不过这道题直接TLE  (nlogn * 快速幂)

           --------------------------------------------------------------------------------

           于是线性筛

           因为积性函数  设 m , n 互质  则 g(mn) =  g(m) * g(n)

           对于 m n 不互质的 现在来解决:

          对于任何 x   g(x) = \prod_{i = 1}^{t}{g(p_i ^ {x_i})}   (把x分解质因子)

 

          推出 g(p_i ^ {x_i}) = \sum_{i = 1}^{x_i}{(p_i ^ {i})^k * u(p^{x_i - {i}})}    =>     g(p_i ^ {x_i}) = (p_i ^ {x_i})^k * u(1) + (p_i^{x_i - 1})^k * u(pi)

          得出 g(p_i^{x_i}) = (p_i^{x_i}) ^ k - (p_i^{x_i - 1}) ^ k

          那么 g(p_i ^ {x_i + 1}) = (p_i^{x_i + 1}) ^ k - (p_i^{x_i}) ^k

          那么 g(p_i ^ {x_i + 1}) = g(p_i ^ {x_i}) * pi ^ k

          对于在线性筛中 会有 g(N * p_i ^ {x_i+1}) != g(N * p_i ^ {x_i}) * g(p_i)   而 g(p_i) = p_i ^ k - 1                                                                               故 g(N * p_i ^ {x_i+1}) == g(N * p_i ^ {x_i}) * (g(p_i) + 1)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int maxn = 5000000;
const int mod = 1000000000 + 7;

LL gxx[maxn + 5];
int pri[maxn + 5];
int miu[maxn + 5];
bool vis[maxn + 5];
int max_id;
int T, K;
bool chk1 = 0;
bool chk2 = 1;
bool chk3 = 1;

LL GetPw(LL n, LL k)
{
    LL res = 1;
    while(k)
    {
        if(k & 1) res *= n, res %= mod;
        n *= n;
        k >>= 1;
        n %= mod;
    }
    return res;
}

void GetMuGx()
{
    miu[1] = 1;
    vis[1] = 1;
    gxx[1] = 1;

    for(int ii = 2;ii <= maxn;ii++)
    {
        if(!vis[ii])
        {
            miu[ii] = -1;
            gxx[ii] = -1 + GetPw(ii, K);
            pri[++max_id] = ii;
        }

        for(int i = 1;i <= max_id;i++)
        {
            int xx = pri[i] * ii;

            if(xx > maxn) break;
            vis[xx] = 1;

            if(ii % pri[i] == 0)
            {
                miu[xx] = 0;
                gxx[xx] = gxx[ii] * (gxx[pri[i]] + 1) % mod;
                break;
            }
            else
            {
                miu[xx] = -miu[ii];
                gxx[xx] = gxx[ii] * gxx[pri[i]] % mod;
            }
        }
    }

    for(int i = 1;i <= maxn;i++) gxx[i] += gxx[i - 1], gxx[i] %= mod;
}

int main()
{
    scanf("%d%d", &T, &K);
    GetMuGx();
    if(chk1) printf("test pw: %d\n", (int)GetPw(2, 5000000));
    if(chk1) for(int i = 4999900;i <= 4999910;i++) printf("gxx[%d] = %lld\n", i, gxx[i]);

    while(T--)
    {
        LL res = 0;
        int m, n, mm;

        scanf("%d%d", &m, &n);
        mm = min(m, n);
        for(int ii = 1, last;ii <= mm;ii = last + 1)
        {
            last = min(n / (n / ii), m / (m / ii));
            res += ((gxx[last] - gxx[ii - 1]) % mod) * (((LL)n / ii) * ((LL)m / ii) % mod) % mod;
            res %= mod;
        }
        res = (res + mod) % mod;
        printf("%lld\n", res);
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值