一个小知识点,昨天遇到了发现自己一直没学过。
整除分块。
Time:o(sqrt(n))
应用场景
:给定了一个数x,想要得到x除以从1到x所有数的结果的时候可以用到,举一个x为20的例子
结论:
可以发现的是,越是到了后方,越能发现很多连在一起的数被x除了之后得出的答案是一样的。
实现:
我们是否可以利用代码来枚举出来呢。
for(int l=a,r=a;l<=b;l=r)
{
r=b/(b/l);
r+=(r==l);
int k=b/l;
}
代码中的k就是我们要求的倍数,l和r代表的是:x除以一段区间内所有数都得出相同的值,那么这段区间的左右端点是多少,当然我们想要k不重复的话直接利用下面这段代码也可以
for(int l=a,r=a;l<=b;l=r+1)
{
r=b/(b/l);
int k=b/l;
}
所以,,很简单,对吧。
例题:
题意:给定一个a和一个b,求出最小的x+y,使得(b+y)%(a+x)==0
思路:从小到大枚举a,假设当前枚举值是A,kA是A的倍数中最接近b的那个数,然后求出a变成A的花费为X,b变成kA的花费为Y。
那么重点就是如何枚举这个A呢?我们发现反正是要用到k*A和b去比较,所以如果两个不同的A/b得到了同一个k的话实际上是无效的,所以要尽量避免无用的A枚举。
Time:O(sqrt(n)*T)
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t,a,b,k,w,ans;
for(cin>>t;t;t--)
{
cin>>a>>b;
if(a>=b)
{
cout<<a-b<<endl;
continue;
}
ans=2e9+100;
for(int l=a,r=a;l<=b;l=r)
{
r=b/(b/l);
r+=(r==l);
k=b/l;
if(b%l) k++;
w=l-a+k*l-b;
w<ans?ans=w:0;
}
cout<<ans<<endl;
}
return 0;
}