T48568 【zzy】yyy送礼物

数论题。。。

来源:luogu秋令营的模拟赛1T2

这道题数据极大,\(N,T \leq 10000000\)

求的是\(\sum_{i=1}^{n}{n \mod i}\)

看上去就是余数求和。打那道题的除法分块做法有70分。

接下来介绍满分做法:

变成这个式子:

\[\sum_{i=1}^n{\lfloor \frac{n}{i} \rfloor \times i}=\sum_{i=1}^n{d_1(i)}\]

\(d_1(x)\)表示\(x\)的约数和。

这个东西可以用线性筛顺便搞出来。

这里粘两个博客,讲得很好,我就不讲了。。。

https://blog.csdn.net/controlbear/article/details/77527115

https://blog.csdn.net/wu_tongtong/article/details/79684277

所以可以线性求出这个东西,弄下前缀和。

然后用\(n^2\)减掉这个东西就是答案了。

代码:

#include<cstdio>

#define ll long long
const int maxn = 10000005;
const int N = maxn - 5;
bool notprime[maxn];
int prime[maxn], tot;
ll sd[maxn], sp[maxn];
ll pre[maxn];
ll read()
{
    ll ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
    return s * ans;
}
void init()
{
    notprime[1] = true; sd[1] = 1; sp[1] = 1;
    for(int i = 2; i <= N; i++)
    {
        if(!notprime[i])
        {
            prime[++tot] = i;
            sd[i] = i + 1;
            sp[i] = i + 1;
        }
        for(int j = 1; j <= tot && i * prime[j] <= N; j++)
        {
            notprime[i * prime[j]] = true;
            if(i % prime[j] == 0)
            {
                sd[i * prime[j]] = sd[i] / sp[i] * (sp[i] * prime[j] + 1);
                sp[i * prime[j]] = sp[i] * prime[j] + 1;
                break;
            }
            else
            {
                sd[i * prime[j]] = sd[i] * sd[prime[j]];
                sp[i * prime[j]] = 1 + prime[j];
            }
        }
    }
    for(int i = 1; i <= N; i++) pre[i] = pre[i - 1] + sd[i];
}
int main()
{
    init();
    ll T = read();
    while(T--)
    {
        ll n = read();
        printf("%lld\n", n * n - pre[n]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9748916.html