推公式真有意思(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。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }