《洛谷P2261 [CQOI2007]余数求和》

推公式真有意思(bushi

题意:求解$ans = sum_{i = 1}^{n} k~mod~i$

这里n,k都很大,O(n)显然会TLE。

我们对这个式子进行一下化简$ans = sum_{i = 1}^{n} k~mod~i ightarrow sum_{i = 1}^{n}k - [frac{k}{i}] * i$//看成整除后剩下的余数。

可以发现,这里的k只是一个不变的常数,所以又可以变形。

$ans = sum_{i = 1}^{n} k - sum_{i = 1}^{n}[frac{k}{i}] * i ightarrow n * k  - sum_{i = 1}^{n}[frac{k}{i}] * i$

可以发现,后面的式子就可以分块来处理了。

对于每个块,他们的k / i都相同,那么就可以提出k / i 即为 块的大小 * i.

这里需要注意的就是边界,因为边界是n,但是k去除,r可能会变0,也可以会超出n。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<double,int> pii;
const int N = 1e6+5;
const int M = 1e6+5;
const LL Mod = 1e9+7;
#define rg register
#define pi acos(-1)
#define INF 1e9
#define CT0 cin.tie(0),cout.tie(0)
#define IO ios::sync_with_stdio(false)
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    void print(int x){
        if(x < 0){x = -x;putchar('-');}
        if(x > 9) print(x/10);
        putchar(x%10+'0');
    }
}
using namespace FASTIO;

int main()
{
    LL n,k;n = read(),k = read();
    LL sum = 0;
    for(LL L = 1,r = 0;L <= n;L = r + 1)
    {
        if(k / L == 0) r = n;
        else r = min(n,k / (k / L));
        LL ma = k / L;
        LL pre = (r + L) * (r - L + 1) / 2;
        sum += ma * pre;
    }
    printf("%lld
",n * k - sum);
    system("pause");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/zwjzwj/p/13814449.html