简要题意:
求:
∑ i = 1 n 2 σ 2 ( i ) + 3 σ 1 ( i ) + 5 i \sum_{i=1}^n 2 \sigma_2(i) + 3 \sigma_1(i) + 5 i i=1∑n2σ2(i)+3σ1(i)+5i
其中 σ k ( x ) = ∑ i = 1 x i k [ x % i = = 0 ] \sigma_k(x) = \sum_{i=1}^x i^k [x \% i ==0] σk(x)=∑i=1xik[x%i==0],即 x x x 所有因数的 k k k 次方和。
推式子:
∑ i = 1 n 2 σ 2 ( i ) + 3 σ 1 ( i ) + 5 i \sum_{i=1}^n 2 \sigma_2(i) + 3 \sigma_1(i) + 5i i=1∑n2σ2(i)+3σ1(i)+5i
= ∑ i = 1 n ( 2 i 2 + 3 i + 5 ) × ⌊ n i ⌋ = \sum_{i=1}^ n (2i^2 + 3i + 5) \times \lfloor \frac{n}{i} \rfloor =i=1∑n(2i2+3i+5)×⌊in⌋
(计算每个因子 i i i 对其它数的贡献)
然后你发现这个式子和整除分块很像。
如果不会可以去 浅谈整除分块 学习一下呦。
好,现在会了 整除分块,你发现你需要高效计算的是:
∑ i = l r ( 2 i 2 + 3 i + 5 ) \sum_{i=l}^r (2i^2 + 3i+5) i=l∑r(2i2+3i+5)
= 2 × ∑ i = l r i 2 + 3 × ∑ i = l r i + 5 × ∑ i = l r 1 = 2 \times \sum_{i=l}^r i^2 + 3 \times \sum_{i=l}^r i + 5 \times \sum_{i=l}^r 1 =2×i=l∑ri2+3×i=l∑ri+5×i=l∑r1
= 2 × ( ∑ i = 1 r i 2 − ∑ i = 1 l − 1 i 2 ) + 3 × ( ∑ i = 1 r i − ∑ i = 1 l − 1 i ) + 5 × ( ∑ i = 1 r 1 − ∑ i = 1 l − 1 1 ) = 2 \times (\sum_{i=1}^r i^2 - \sum_{i=1}^{l-1} i^2) + 3 \times (\sum_{i=1}^r i - \sum_{i=1}^{l-1} i) + 5 \times (\sum_{i=1}^r 1 - \sum_{i=1}^{l-1} 1) =2×(i=1∑ri2−i=1∑l−1i2)+3×(i=1∑ri−i=1∑l−1i)+5×(i=1∑r1−i=1∑l−11)
= 2 × ( r × ( r + 1 ) × ( 2 r + 1 ) 6 − l × ( l − 1 ) × ( 2 l − 1 ) 6 ) + 3 × ( r × ( r + 1 ) 2 − l × ( l − 1 ) 2 ) + 5 × ( r − l + 1 ) = 2 \times ( \frac{r \times (r+1) \times (2r+1)}{6} - \frac{l \times (l-1) \times (2l-1)}{6})+ 3 \times (\frac{r \times (r+1)}{2} - \frac{l \times (l-1)}{2}) + 5 \times (r-l+1) =2×(6r×(r+1)×(2r+1)−6l×(l−1)×(2l−1))+3×(2r×(r+1)−2l×(l−1))+5×(r−l+1)
然后你发现这可以 O ( 1 ) O(1) O(1) 计算。(学会小学数学公式真有用~)
时间复杂度: O ( n ) O(\sqrt{n}) O(n)
实际得分: 100 p t s 100pts 100pts.
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=998244353;
inline ll read(){char ch=getchar();ll f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
ll x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
ll n,ans=0;
inline ll count(ll l,ll r) {
__int128 x=(((__int128)r*(r+1)*(2*r+1) - (__int128)(l-1)*l*(2*l-1))/3)%MOD; //平方
x=(x<0)?(x+MOD):x;
__int128 y=((__int128)(3*(l+r)*(r-l+1))/2)%MOD; //一次项
y=(y<0)?(y+MOD):y;
__int128 z=(5*(r-l+1))%MOD; //常数项
z=(z<0)?(z+MOD):z;
__int128 tot=(((__int128)(x+y+z)%MOD)*(n/l))%MOD;
return (ll)(tot<0)?(tot+MOD):tot;
} //好事多模
int main(){
n=read();
ll l=1,r;
for(l=1;l<=n;l=r+1) { //整除分块模板
r=n/(n/l);
ans=(ans+count(l,r))%MOD;
} printf("%lld\n",ans);
return 0;
}