传奇模数 题解
其实官方题解已经讲得很好了,自己就是补充一下,顺便说一下自己赛时思路。
1.题意
同官方题解,在这里我们定义
对于正整数
2.我会暴力
枚举 但是很可惜,考场上我想不出这个。
只得赛后打个代码给各位献丑:
#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.转向规律
既然暴力不行,那就找找规律。
我们注意到:
- 若
1\le i < p ,显然\lfloor \frac{i}{p} \rfloor =0 。 - 若
p\le i < 2p ,显然\lfloor \frac{i}{p} \rfloor =1 。 - 若
2p\le i < 3p ,显然\lfloor \frac{i}{p} \rfloor =2 。 -
\dots - 满足
k 为正整数,若kp\le i\le n<(k+1)p ,显然\lfloor \frac{i}{p} \rfloor =k 。
所以,不必要一一枚举,只需每次加上
赛时代码加了些注释,由于太紧张,码风不太好,见谅:
#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 ;
}
上交一测,结果:
怎么回事?
4.数学优化
令
for (int i = 0 ; i < x ; i ++) {
ans += i * p ;
ans %= mod ;
}
不难看出:
根据小学二年级就学过的等差数列求和公式
放上赛时稍加修改的代码:
#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 ;
}