• 博客园logo
  • 会员
  • 周边
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
magicat
博客园    首页    新随笔    联系   管理    订阅  订阅
数论分块总结

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]余数求和

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

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

posted on 2023-05-08 10:32  magicat  阅读(62)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3