因为一道题看别人代码看不懂而到处问大佬指路
先给出题
题意:如图所示,第i块的面积为i^2,price(i)如图所示,计算买n片田所需的钱
总结:t=100,n=1e9,显然不能暴力,赛时的第一想法是大概是个O(t*根号n)的复杂度,但是完全没有思路。
那如果把1e9这么长的一段区间优化掉呢。
需要用到数论分块的知识。
【数论】数论分块 - BeautifulWater - 博客园
了解完数论分块的知识后,我们就能将n这么长的一段区间变成根号n级别的了;
for(int l=1,r,r<=n;r=l+1){
r=n/(n/l);//枚举相同值的右端点
int len=r-l+1;//长度
}
基本模板就是这样子。
我们回到原题。
有了前置知识,我们就不难搞定这道题了,只需要求出每一段i^2的总和,我们就可在合理的复杂度内解决问题。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
ll inv6=qpow(6,mod-2);
ll cal(int l,int r){
l-=1;
ll ans1=1ll*l*(l+1)%mod*(2*l%mod+1)%mod*inv6%mod;
ll ans2=1ll*r*(r+1)%mod*(2*r%mod+1)%mod*inv6%mod;
return ((ans2-ans1)%mod+mod)%mod;
}
int main(){
int t;
cin>>t;
while(t--){
ll ans=0;
int n;
cin>>n;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
int len=r-l+1;
int val=n/l+1;
ans=(ans+1ll*val*cal(l,r)%mod)%mod;
//由于是向上取整,而数论分块是向下,所以值要加1;
if(n%r==0)ans=(ans-1ll*r*r%mod+mod)%mod;//取到的右端点刚好整除n,减掉他的贡献
}
cout<<ans<<endl;
}
}