Fair Distribution
有n个机器人,m个能量条,能够进行两种操作,n–或m++,每次操作花费1美元,求使得m%n=0的最小花费
设
n
减
少
了
x
,
则
花
费
为
n
−
(
n
−
x
)
+
(
[
m
−
1
n
−
x
]
+
1
)
∗
(
n
−
x
)
−
m
=
n
−
m
+
[
m
−
1
n
−
x
]
∗
(
n
−
x
)
,
m
i
n
(
[
m
−
1
n
−
x
]
∗
(
n
−
x
)
)
可
以
用
整
除
分
块
O
(
n
)
来
求
得
。
对
于
[
n
i
]
设n减少了x,则花费为 n-(n-x)+( [\frac{m-1}{n-x}]+1)*(n-x)-m= n-m+[\frac{m-1}{n-x}]*(n-x),min([\frac{m-1}{n-x}]*(n-x))可以用整除分块O(\sqrt n)来求得。对于[\frac{n}{i}]
设n减少了x,则花费为n−(n−x)+([n−xm−1]+1)∗(n−x)−m=n−m+[n−xm−1]∗(n−x),min([n−xm−1]∗(n−x))可以用整除分块O(n)来求得。对于[in],
显
然
会
有
很
多
i
的
值
是
相
同
的
,
那
么
把
这
些
i
分
成
一
块
,
只
用
求
一
次
就
行
了
显然会有很多i的值是相同的,那么把这些i分成一块,只用求一次就行了
显然会有很多i的值是相同的,那么把这些i分成一块,只用求一次就行了
,
但
是
要
知
道
这
个
块
的
起
始
位
置
,
开
始
位
置
是
我
们
要
枚
举
的
,
结
束
位
置
为
n
/
(
n
/
i
)
.
,但是要知道这个块的起始位置,开始位置是我们要枚举的,结束位置为n/(n/i).
,但是要知道这个块的起始位置,开始位置是我们要枚举的,结束位置为n/(n/i).
#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
using namespace std;
const int N = 1e6+ 7;
const int M = 50+7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
typedef long long ll;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
int ans=inf;
scanf("%d%d",&n,&m);
if(n>=m)
{
printf("%d\n",n-m);
}
else
{
for(int l=1,r;l<=n;l=r+1){
r=min(n,(m-1)/((m-1)/l));
ans=min(ans,(m-1)/l*l);
}
printf("%d\n",ans+n-m);
}
}
return 0;
}
其他可以用整除分块的题目
约数研究
看起来和整除分块没啥关系,因为一眼看过去根本没有
∑
n
i
\sum\frac{n}{i}
∑in,但是
∑
f
(
i
)
是
可
以
转
化
成
∑
n
i
\sum f(i)是可以转化成\sum\frac{n}{i}
∑f(i)是可以转化成∑in的,
∑
1
n
f
(
i
)
=
∑
i
=
1
n
i
的
约
数
,
i
的
约
数
=
∑
1
n
[
j
∣
i
]
,
即
能
被
i
整
除
的
数
的
个
数
,
=
∑
i
=
1
n
∑
j
=
1
n
[
j
∣
i
]
=
∑
j
=
1
n
∑
i
=
1
n
[
j
∣
i
]
,
这
里
就
变
成
了
能
整
除
j
的
个
数
,
那
么
显
然
1
−
n
中
能
整
除
j
的
个
数
为
n
j
,
所
以
原
式
化
为
∑
n
j
,
然
后
就
可
以
用
整
除
分
块
了
。
\sum_1^n f(i)=\sum_{i=1}^ni的约数,i的约数=\sum_1^n[j|i],即能被i整除的数的个数,=\sum_{i=1}^{n}\sum_{j=1}^{n}[j|i]=\sum_{j=1}^{n}\sum_{i=1}^{n}[j|i],这里就变成了能整除j的个数,那么显然1-n中能整除j的个数为\frac{n}{j},所以原式化为\sum\frac{n}{j},然后就可以用整除分块了。
∑1nf(i)=∑i=1ni的约数,i的约数=∑1n[j∣i],即能被i整除的数的个数,=∑i=1n∑j=1n[j∣i]=∑j=1n∑i=1n[j∣i],这里就变成了能整除j的个数,那么显然1−n中能整除j的个数为jn,所以原式化为∑jn,然后就可以用整除分块了。
#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
using namespace std;
const int N = 1e6+ 7;
const int M = 50+7;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
typedef long long ll;
int main()
{
int n;
scanf("%d",&n);
int ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
printf("%d\n",ans);
return 0;
}
Calculating
和上一题差不多,就是要减去
[
1
,
l
]
[1,l]
[1,l]的。
#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
using namespace std;
const int N = 1e6+ 7;
const int M = 50+7;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll ans1=0,ans2=0;
for(ll l=1,r;l<n;l=r+1){
r=(n-1)/((n-1)/l);
ans1+=(r-l+1+mod)%mod*((n-1)/l);
ans1%=mod;
}
for(ll l=1,r;l<=m;l=r+1){
r=m/(m/l);
ans2+=(r-l+1+mod)%mod*(m/l);
ans2%=mod;
}
printf("%lld\n",(ans2-ans1+mod)%mod);
return 0;
}