(2019多校第一场)hdu6588 Function

题意


\[ \sum_{i=1}^ngcd(\lfloor\sqrt[3]i\rfloor, i) \]
\(n \leq 10^{21}\)

官方题解讲的大部分都很明白了,主要是有两个地方有点莫名其妙,想了整整七天才想明白。。。是我太菜了

记\(m=\lfloor\sqrt[3]n\rfloor\)

原式

\(=\sum_{a=1}^{m-1}\sum_{i=a^3}^{(a+1)^3-1}gcd(a,i)+\sum_{i=m^3}^ngcd(m,i)\)

设\(f(a, n)=\sum_{i=1}^ngcd(a,i)\)

则\(f(a,n)=\sum_{d|a}d\sum_{i=1}^{\frac{n}{d}}[gcd(\frac{a}{d},i)==1]=\sum_{d|a}d\sum_{e|\frac{a}{d}}\mu(e)\lfloor\frac{n}{de}\rfloor\)

这个是反演演出来的。。。理解成容斥也可以。。。

然后第一个摸不着头脑的地方是下一步。。。下一步最关键的是要去设\(T=de\),观察到上式枚举的\(d,e\)是\(a\)的两个“不相交”的因子(意会一下XD)

所以\(T|a,d|T\),因此实际上可以变换成

\(f(a,n)=\sum_{T|a}\sum_{d|T}d\mu(\frac{T}{d})\lfloor\frac{n}{T}\rfloor=\sum_{T|a}\lfloor\frac{n}{T}\rfloor\sum_{d|T}d\mu(\frac{T}{d})\)

后面那个是个公式,等于\(\varphi(T)\),所以\(f(a,n) = \sum_{T|a}\lfloor\frac{n}{T}\rfloor\varphi(T)\)

这个\(O(\sqrt n)\)搞定

接下来是答案的前半部分,代入\(f(a,(a+1)^3-1)-f(a,a^3-1)\)得

\(\sum_{a=1}^{m-1}\sum_{T|a}\varphi(T)(\lfloor\frac{(a+1)^3-1}{T}\rfloor-\lfloor\frac{a^3-1}{T}\rfloor)\)

下一步设\(a=bT\),交换两个求和符号也有点摸不着头脑。。。意思就是从先枚举\(a\)改为先枚举\(T\)小于等于\(m-1\)再枚举小于等于\(m-1\)的\(T\)的倍数\(a\),也就相当于枚举\(b\)从1到\(\lfloor\frac{m-1}{T}\rfloor\).

然后那一通拆括号变形计算就略了,设\(y = \lfloor\frac{m-1}{T}\rfloor\)最后答案是
\[ \sum_{T=1}^{m-1}\varphi(T)[3T\sum_{b=1}^yb^2+3\sum_{b=1}^yb+\sum_{b=1}^y1] \]
里面的三个都直接套公式求和就搞定了。。

我写的太丑了,全改成int128会T...还要注意一下能用ll就别用int128

#include <bits/stdc++.h>
#define LL long long
#define MAXN 10000000
using namespace std;
const LL mod = 998244353;
const LL inv6 = 166374059, inv2 = 499122177;
LL gcd(LL a, LL b)
{
    return b?gcd(b, a%b):a;
}

int prime[MAXN + 8];
int phi[MAXN + 8];
bool notprime[MAXN + 8];
int ind = 0;
void getprime()
{
    notprime[1] = true;
    phi[1] = 1;
    for (int i = 2; i <= MAXN; ++i)
    {
        if (!notprime[i])
        {
            prime[++ind] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= ind && i * prime[j] <= MAXN; ++j)
        {
            notprime[i * prime[j]] = true;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
}
__int128_t n;

LL tripleroot(__int128_t n)
{
    __int128_t l = 1, r = 100000000;
    while (l < r)
    {
        __int128_t mid = (l + r) / 2;
        if (mid * mid * mid < n)
            l = mid + 1;
        else
            r = mid;
    }
    return (LL)(l - (l * l * l > n));
}

LL f(LL a, __int128_t n)
{
    LL ret = 0;
    for (LL T = 1; T * T <= a; ++T)
    {
        if (a % T) continue;
        ret = (ret + (n / T) * phi[T] % mod) % mod;
        if (T * T != a)
        {
            LL B = a / T;
            ret = (ret + (n / B) * phi[B] % mod) % mod;
        }
    }
    return ret;
}

template <class T>
void read(T &x) {
    static char ch;static bool neg;
    for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
    for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
    x=neg?-x:x;
}
int main()
{
    getprime();
    int __;
    read(__);
    while (__--)
    {
        read(n);
        if (n <= 7)
        {
            LL ret = 0;
            for (LL i = 1; i <= n; ++i)
                ret += gcd(1, i);
            cout << ret << endl;
            continue;
        }
        LL m = tripleroot(n);
        LL ans = (f(m, n) - f(m, (__int128_t)m * m * m - 1) + mod) % mod;
        for (LL T = 1; T <= m - 1; ++T)
        {
            LL y = (m - 1) / T;
            ans = (ans + phi[T] * (((3 * T % mod * y % mod * (y + 1) % mod * (2 * y + 1) % mod * inv6 % mod)
                                   + (3 * y % mod * (y + 1) % mod * inv2 % mod)
                                   + y) % mod) % mod) % mod;
        }
        cout << ans << endl;
    }
}
上一篇:Flink 流处理API之二


下一篇:CF1539F - Strange Array(线段树)