AtCoder abc230_e E - Fraction Floor Sum
AtCoder abc230_e Fraction Floor Sum
求:
\[\sum_{i = 1}^N ⌊\dfrac{N}{i}⌋
\]
是一个很裸的数论分块
ll ans = 0;
void solve()
{
ll n; cin>>n;
for(ll l = 1; l <= n; l++)
{
ll d = n / l, r = n / d;
ans += (r - l + 1) * d;
l = r;
}
cout<<ans<<endl;
return;
}
P2261 [CQOI2007]余数求和
化简一下:
\[G(n, k) = \sum_{i = 1}^n k \bmod i = \sum_{i = 1}^n (k - i \times⌊\dfrac{k}{i} ⌋) = n \times k - \sum_{i = 1}^n i \times⌊\dfrac{k}{i}⌋
\]
- 发现$\sum_{i = 1}^n i \times⌊\dfrac{k}{i}⌋ $可以数论分块来做
- 式子\(i \times⌊\dfrac{k}{i}⌋\) 中\(⌊\dfrac{k}{i}⌋\) 是确定的,对于\([l, r]\)的贡献区间用一个等差数列前n项和数列解决
ll n, k;
void solve()
{
cin>>n>>k;
ll res = n * k;
for(ll l = 1; l <= n; l++)
{
ll d = k / l, r;
if(d == 0)
r = n;
else
r = min(n, k / d);
ll m = r - l + 1;
res -= d * (l + r) * m / 2;
l = r;
}
cout<<res<<endl;
}
The 18th Zhejiang Provincial Collegiate Programming Contest F. Fair Distribution
参考:Fair Distribution(分块除法),x / k向上取整转换为向下取整
操作可以减少\(n\),增加\(m\),求最小操作数使得\(m \bmod n = 0\)
设 \(m\) 的操作数为:\(⌈\dfrac{m}{n -x} ⌉ \times (n - x) - m\)
设 \(n\) 的操作数: \(x\)
则\(\text{ans} = ⌈\dfrac{m}{n - x} ⌉ \times (n - x) - m + x\)
设 \(l = n - x\),则有\(x = n - l\)
即:
\[⌈\dfrac{m}{n - x} ⌉ \times (n - x) - m + x = ⌈\dfrac{m}{l} ⌉ \times l - m + n - l
\]
这里有一个\(-l\)直接用数论分块做不了,我们用向上取整转化成向下取整消去,向上取整转化成向下取整有这样的公式:
\[⌈\dfrac{x}{k} ⌉ = ⌊\dfrac{x + k - 1}{k} ⌋
\]
这里还有减去一个\(l\)
\[⌈\dfrac{m}{l}⌉ \times l - l = ⌊\dfrac{m - 1}{l} ⌋ \times l
\]
所以:
\[⌈\dfrac{m}{n - x} ⌉ \times (n - x) - m + x = ⌊\dfrac{m - 1}{l} ⌋ \times l - m + n
\]
然后进行数论分块
ll n, m;
void solve()
{
cin>>n>>m;
if(m % n == 0)
{
cout<<0<<endl;
return;
}
else if(m < n)
{
cout<<n - m<<endl;
return;
}
ll res = 1e18;
for(ll l = 1; l <= n; l++)
{
ll d = (m - 1) / l, r;
if((m - 1) / d == 0)
r = n;
else
r = (m - 1) / d;
res = min(res, (m - 1) / l * l - m + n);
l = r;
}
cout<<res<<endl;
}
本文来自博客园,作者:magicat,转载请注明原文链接:https://www.cnblogs.com/magicat/p/17380982.html