专栏文章

传奇模数 题解

P13679题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miodzfot
此快照首次捕获于
2025/12/02 17:39
3 个月前
此快照最后确认于
2025/12/02 17:39
3 个月前
查看原文
其实官方题解已经讲得很好了,自己就是补充一下,顺便说一下自己赛时思路。

1.题意

同官方题解,在这里我们定义 p=998244353p=998244353
对于正整数 nn,求 (1p+2p++np)modp\left(\lfloor\dfrac{1}{p}\rfloor+\lfloor\dfrac{2}{p}\rfloor+\dots+\lfloor\dfrac{n}{p}\rfloor\right)\bmod p

2.我会暴力

枚举 pp11nn,算 i=1nip\sum\limits_{i=1}^{n} \lfloor \frac{i}{p} \rfloor(假如看不懂求和符号西格玛请出门右转看数学百科西格玛稍稍了解一下如何运算即可)。当然也可以稍稍优化一下,从 pp 开始。但是很可惜,考场上我想不出这个
只得赛后打个代码给各位献丑:
CPP
#include <bits/stdc++.h>
#define int long long
using namespace std ;
int n , ans ;
const int p = 998244353 ;
signed main () {
  cin >> n ;
  for (int i = p ; i <= n ; i ++) {
    ans += i / p ;
    ans %= p ;
  }
  cout << ans % p ;
}
竟然优化后有 40 pts!

3.转向规律

既然暴力不行,那就找找规律。
我们注意到:
  • 1i<p1\le i < p,显然 ip=0\lfloor \frac{i}{p} \rfloor =0
  • pi<2pp\le i < 2p,显然 ip=1\lfloor \frac{i}{p} \rfloor =1
  • 2pi<3p2p\le i < 3p,显然 ip=2\lfloor \frac{i}{p} \rfloor =2
  • \dots
  • 满足 kk 为正整数,若 kpin<(k+1)pkp\le i\le n<(k+1)p,显然 ip=k\lfloor \frac{i}{p} \rfloor =k
所以,不必要一一枚举,只需每次加上 pp 就行了,或者枚举到 np\frac{n}{p},只要最后再末尾判断一次就行了。
赛时代码加了些注释,由于太紧张,码风不太好,见谅:
CPP
#include <bits/stdc++.h>
using namespace std ;
#define int long long
const int mod = 998244353 ;
int n , ans ;
signed main () {
    ios::sync_with_stdio (false) ;
    cin.tie (NULL) ; cout.tie (NULL) ;
    cin >> n ;
    int x = n / 998244353 ;
    int y = n % 998244353 ;
    for (int i = 0 ; i < x ; i ++) {  // 枚举到 <x,最后尾判。
        ans += i * 998244353 ; //从 kp 到 (k+1)p 共有 p(在这里是 mod) 个。
        ans %= mod ;
    }
    ans += (y + 1) * x ; //尾判,显然最后有 y+1 个 k=x。  
    cout << ans % mod ;
    return 0 ;
}
上交一测,结果:
80pts
怎么回事?

4.数学优化

x=npx=\frac{n}{p},下面代码:
CPP
for (int i = 0 ; i < x ; i ++) {  
    ans += i * p ; 
    ans %= mod ;
}
不难看出:ans=i=0x1i×pans=\sum\limits_{i=0}^{x-1} i\times p,再进行一些一些操作:
ans=i=0x1i×p=0+p+2p+3p++(x1)p=[1+2++(x1)]p\begin{aligned} ans&=\sum\limits_{i=0}^{x-1} i\times p \\ &=0+p+2p+3p+\dots+(x-1)p \\ &=\left[1+2+\dots+\left(x-1\right)\right]p \\ \end{aligned}
根据小学二年级就学过的等差数列求和公式 S=(a1+an)n2S=\frac{(a_1+a_n)n}{2}nn 为数列的个数),可知:ans=(1+x1)(x1)2×p=x(x1)×p2ans=\frac{(1+x-1)(x-1)}{2}\times p=\frac{x(x-1)\times p}{2},这样复杂度就降为 O(1)\mathcal{O}(1) 了,十分优秀,妈妈再也不会担心我过不了了!
放上赛时稍加修改的代码:
CPP
#include <bits/stdc++.h>
using namespace std ;
#define int long long
const int p = 998244353 ;
int n , ans ;
signed main () {
    ios::sync_with_stdio (false) ;
    cin.tie (NULL) ; cout.tie (NULL) ;
    cin >> n ;
    int x = n / 998244353 ;
    int y = n % 998244353 ;
    ans += x % p * (x - 1) % p * p % p / 2 % p ;
    /*1+x+..+(x-1)=(1+x-1)*(x-1)/2*/
    ans += (y + 1) * x ;
    cout << ans % p ;
    return 0 ;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...