[CSDN同步]
简要题意:
求:
[sum_{i=1}^n 2 sigma_2(i) + 3 sigma_1(i) + 5 i
]
其中 (sigma_k(x) = sum_{i=1}^x i^k [x \% i ==0]),即 (x) 所有因数的 (k) 次方和。
推式子:
[sum_{i=1}^n 2 sigma_2(i) + 3 sigma_1(i) + 5i
]
[= sum_{i=1}^ n (2i^2 + 3i + 5) imes lfloor frac{n}{i}
floor
]
(计算每个因子 (i) 对其它数的贡献)
然后你发现这个式子和整除分块很像。
如果不会可以去 浅谈整除分块 学习一下呦。
好,现在会了 整除分块,你发现你需要高效计算的是:
[sum_{i=l}^r (2i^2 + 3i+5)
]
[= 2 imes sum_{i=l}^r i^2 + 3 imes sum_{i=l}^r i + 5 imes sum_{i=l}^r 1
]
[= 2 imes (sum_{i=1}^r i^2 - sum_{i=1}^{l-1} i^2) + 3 imes (sum_{i=1}^r i - sum_{i=1}^{l-1} i) + 5 imes (sum_{i=1}^r 1 - sum_{i=1}^{l-1} 1)
]
[= 2 imes ( frac{r imes (r+1) imes (2r+1)}{6} - frac{l imes (l-1) imes (2l-1)}{6})+ 3 imes (frac{r imes (r+1)}{2} - frac{l imes (l-1)}{2}) + 5 imes (r-l+1)
]
然后你发现这可以 (O(1)) 计算。(学会小学数学公式真有用~)
时间复杂度:(O(sqrt{n}))
实际得分:(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
",ans);
return 0;
}