数论分块一例题

因为一道题看别人代码看不懂而到处问大佬指路

先给出题

登录—专业IT笔试面试备考平台_牛客网牛客网是互联网求职神器,C++、Java、前端、产品、运营技能学习/备考/求职题库,在线进行百度阿里腾讯网易等互联网名企笔试面试模拟考试练习,和牛人一起讨论经典试题,全面提升你的技术能力icon-default.png?t=M4ADhttps://ac.nowcoder.com/acm/contest/33540/G

 题意:如图所示,第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;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值