一道普及组题目

大家好,我是普及组选手,我又开考就上厕所切了一道普及组题


题意

  给你两个整数 \(n,m\),求 \((\sum\limits_{i=1}^m n\space\text{mod}\space i)\mod (10^9+7)\)
  \(n,m\le 10^{13}\)

sol

  小学生都猜得出来是整除分块裸题
  然后发现对于整除分块的每一块,它们除 \(n\) 后下取整的值都相同,所以它们除 \(n\) 的余数是一个等差数列,公差就是它们除 \(n\) 后下取整的值的相反数
  显然小学生都会等差数列求和,所以整除分块套个等差数列求和公式就做完了
  注意特殊处理 最后一块残缺(即 \(m\) 在某个块中间) 以及 \(n\gt m\) 的情况。

  考后发现爆成 \(70\) 分了
  然后我就暴躁地找了一下问题,发现我取模是这么写的(只取了一行为例)

ans = (ans + 1ll * (n%i+n%j) % mod * (j-i+1) % mod * invmod % mod) % mod;

  显然我注意到了乘数都高达 \(1e13\),所以从第一个乘数开始就取模。
  但是我忘了给后面的乘数取模了……于是 \(1e9\times 1e13\) 就爆 long long 了……
  zbl

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
#define invmod 500000004
using namespace std;
inline ll read(){
    ll x=0; bool f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    if(f) return x;
    return 0-x;
}
ll n,m,ans;
int main(){
    n=read(), m=read();
    ll to=min(n,m),i,j;
    for(i=1,j; i<=n; i=j+1){
        j=n/(n/i);
        if(j>to) break;
        ans = (ans + 1ll * (n%i+n%j) % mod * ((j-i+1)%mod) % mod * invmod % mod) % mod;
    }
    if(i<=to) ans = (ans + 1ll * (n%i+n%m) % mod * ((m-i+1)%mod) % mod * invmod % mod) % mod;
    if(m>n) ans = (ans + 1ll * n % mod * ((m-n)%mod) % mod) % mod;
    cout<<ans<<endl;
    return 0;
}

  当然这题还有小学组方法,但我刚上幼儿园并没想到
782255-20190808195857944-418275841.png

转载于:https://www.cnblogs.com/scx2015noip-as-php/p/190808a.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值