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

推公式真有意思(bushi

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

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

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

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

$ans = \sum_{i = 1}^{n} k - \sum_{i = 1}^{n}[\frac{k}{i}] * i\rightarrow 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",n * k - sum);
    system("pause");
    return 0;
}
View Code

 

posted @ 2020-10-14 13:52  levill  阅读(101)  评论(0编辑  收藏  举报