PE 565

Ans:2992480851924313898
注意到 σ 是积性函数,所以我们考虑唯一分解,然后每一部分形如 apii 的贡献是 1+ai+...+apii ,都可以预处理是否是 2017 的倍数.这里要特别处理 pi=1 的部分,因为数比较多。我们注意到 pi=1 时合法当且仅当 ai mod 2017=2016 ,所以用筛法就行了。剩下的容斥。注意到每个预处理出来的数的基数都不一样(如果在1e12的级别就有一样的了。。。),且没有一个数可以拥有三个预处理出来的数的乘积的因子。所以我们暴力枚举一个还是两个进行容斥。注意积性函数并非完全积性函数,所以我们还要去掉两个相同的数的乘积。最后,一开始的筛法的第一个数定位我们可以用exgcd。
15s左右,我也不知道复杂度。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll n = 1e11, k = 2017;

bool B[50000010], B2[5000010];

struct node
{
    ll x, y;
    node() {} node(ll _, ll __) {x = _, y = __;}
    bool operator < (const node& X) const {return x < X.x;}
} L[50000010];

ll t = 0, ans = 0;

void exgcd(ll a, ll& x, ll b, ll& y)
{
    if(!b) x = 1, y = 0; else exgcd(b, y, a % b, x), y -= a / b * x;
}

ll calc(ll a)
{
    ll x, y;
    exgcd(k, x, a, y);
    return (x % a + a) % a;
}

ll calc2(ll a) {return (a + n / a * a) * (n / a);}

ll S(ll a) {return a * (a + 1) / 2;}

int main()
{
    ll tmp1 = n / k, tmp2 = sqrt(n);
    for(int i = 2; i <= tmp2; i++) {
        if(!B2[i]) for(int j = i + i; j <= tmp2; j += i) B2[j] = 1;
        if(i % k) for(int j = calc(i); j <= tmp1; j += i) if(j * k != i + 1) B[j] = 1;
    }
    for(int i = 1; i <= tmp1; i++) if(!B[i]) L[++t] = node(k * i - 1, k * i - 1);
    for(ll i = 2; i <= tmp2; i++) if(!B2[i] && i % k != k - 1)
        for(ll j = i * i, s = 1 + i; j <= n; j *= i)
            if((s += j) % k == 0) L[++t] = node(j, i);
    printf("%lld\n", t);
    sort(L + 1, L + t + 1);
    for(int i = 1; i <= t; i++) ans += L[i].x * S(n / L[i].x);
    for(int i = 1; i <= t; i++)
        if(L[i].x * L[i].y <= n) ans -= L[i].x * L[i].y * S(n / L[i].x / L[i].y);
    for(int i = 1; i <= t; i++)
        for(int j = i + 1; j <= t; j++)
            if(L[i].x > n / L[j].x) break; else ans -= L[i].x * L[j].x * S(n / L[i].x / L[j].x);
    printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值