「Gym-102803H」Hate That You Know Me

题目概述

给定 a,b,na,b{0,1,2,3}n1012 ,求

(i=1nd|ndai=1nd|ndb)

思路&&做法

首先观察到题目需要求从 1n 的每个数的因数的 k 次方和,对于这种题,我们有一个思考方向是考虑计算贡献。

可以发现对于 x ,它会在它的倍数的地方计算一次贡献,假设当前是求 k 次方,则 x 的贡献就是 xk×nx

但我们显然不能枚举 x ,所以要思考怎么计算这个式子。结合式子中的向下取整以及 n1012 的范围,我们可以联想到整除分块,对于整除分块,我们可以分出 O(n)nx相等的块,并且每个块中的 x 是连续的,假设某一个块的区间是 [l,r] ,该区间的贡献即 nx×i=lrik ,注意到本题 a,b3 ,所以是有区间 k 次方和的公式的,这时我们只需动动小手,上网一查即可。

  • i=lri0=rl+1
  • i=lri1=(r+l)×(rl+1)2
  • i=1ni2=n×(n+1)×(2n+1)6
  • i=1ni3=(n×(n+1)2)2

对于 k 次方和,有兴趣可以看下这篇博客

/*
address:https://vjudge.net/problem/Gym-102803H

*/
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e6 + 5;
int a, b;
ULL n;
inline ULL calc(ULL l, ULL r, int x) {
    if (x == 0) return r - l + 1;
    if (x == 1) return (l + r) * (r - l + 1) / 2;
    if (x == 2) return (r * (r + 1) * (2 * r + 1) / 6) - ((l - 1) * (l) * (l * 2 - 1) / 6);
    if (x == 3) return (r * (r + 1) / 2) * (r * (r + 1) / 2) - (l * (r - 1) / 2) * (l * (r - 1) / 2);
}
int main() {
    scanf("%d%d%llu", &a, &b, &n);
    ULL x = 0, y = 0;
    for (ULL L = 1, R = 1;n / L;L = R + 1) {
        R = n / (n / L);
        x += calc(L, R, a) * (n / L);
        y += calc(L, R, b) * (n / L);
    }
    printf("%llu", x ^ y);
    return 0;
}

完结撒花……了吗?

如果此时你交一发,会发现自己神奇的 WA 在了第 3 个点。

仔细观察,代码中计算的部分是有除法的,在取模的情况下不能进行除法,然后我们又悲催地发现模数不是质数,还不保证互质,所以乘法逆元不可行。但我们知道,是在乘完取模后不能除,而我们在除的时候是在计算一个固定值,并不是边乘边取,所以我们可以在乘上两个数取模之前先把要除的数除掉就行。

/*
address:https://vjudge.net/problem/Gym-102803H
AC 2025/2/8 14:53
*/
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e6 + 5;
int a, b;
ULL n;
inline ULL calc(ULL l, ULL r, int x) {
    ULL ret = 1;
    if (x == 0) return r - l + 1;
    if (x == 1) {
        ULL x = l + r, y = r - l + 1;
        if (!(x & 1)) x /= 2;
        else y /= 2;
        return x * y;
    }
    if (x == 2) {
        ULL x = r, y = r + 1, z = 2 * r + 1;
        if (x % 2 == 0) x /= 2;
        else if (y % 2 == 0) y /= 2;
        else z /= 2;
        if (x % 3 == 0) x /= 3;
        else if (y % 3 == 0) y /= 3;
        else z /= 3;
        ret = x * y * z;
        x = l - 1, y = l, z = l * 2 - 1;
        if (!(x & 1)) x /= 2;
        else if (!(y & 1)) y /= 2;
        else z /= 2;
        if (x % 3 == 0) x /= 3;
        else if (y % 3 == 0) y /= 3;
        else z /= 3;
        ret -= x * y * z;
        return ret;
    }
    if (x == 3) {
        if (r & 1) ret = ((r + 1) / 2) * ((r + 1) / 2) * r * r;
        else ret = (r / 2) * (r / 2) * (r + 1) * (r + 1);
        ULL del;
        if (l & 1) del = ((l - 1) / 2) * ((l - 1) / 2) * l * l;
        else del = (l / 2) * (l / 2) * (l - 1) * (l - 1);
        ret -= del;
        return ret;
    }
}
int main() {
    scanf("%d%d%llu", &a, &b, &n);
    ULL x = 0, y = 0;
    for (ULL L = 1, R = 1;n / L;L = R + 1) {
        R = n / (n / L);
        x += calc(L, R, a) * (n / L);
        y += calc(L, R, b) * (n / L);
    }
    printf("%llu", x ^ y);
    return 0;
}

这道题不难,就是中间要在取模前除有点坑。

posted @   keysky  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示