陕西省第九届大学生程序设计竞赛 C.GCD 整除分块
作者:互联网
这题值得好好写写:
很快想到了如果一堆数的公因数都是a,那么必定都是a的倍数(废话)
那么如果在[l,r]里找到最小的a的倍数,再逐渐+a,+2*a,得到的一堆数必定gcd==a的条件
而且,这些数的个数还要至少为k
问题转化成了求a,a满足[l,r]里面是a的倍数的数大于等于k个
plan A:
写了个枚举,a的最大值是(r-l+1)/k;
当然狠狠地超时了
plan B:
看了题解后明白了一种叫差分的思想和一种叫整除分块的东西
差分思想:其实是 r/a-(l-1)/a>=k
没想到这个,我连分块都摸不到hhh(安慰自己想不到hin正常
观察r/a:
——by pengym 侵删
这里r就是n,a就是i。
说明r/a的值是有限的,且同一个r/a,可能对应了好几个a
那是不是,用整除分块可以把a切成一块块的,在每个块里面,r/a的值和(l-1)/a的值是固定的,只要check一下满不满足>=k这个条件,就可以直接计算这个块的贡献:
这个块的长度!
但是实现起来,emmm:
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll l,r,k; map<ll,ll>Hash; int main() { ll ans=0; cin>>l>>r>>k; l--; for(ll L=1,R;L<=r;L=R+1) { R=r/(r/L); ll v1=r/L; ll v2=l/L; if(v2) R=min(R,l/v2); if(v1-v2>=k) ans+=(R-L)+1; } cout<<ans; }
我们发现如果没有这部分,是会卡在89tps的:
ll v1=r/L; ll v2=l/L; if(v2) R=min(R,l/v2);
把每次l/v2和r/v1的结果打出来,发现v1和v2的大小关系不确定
就是说我们有l,还有r,每个数都有自己的分块切法,显然不会完全相同
那当然是取右边界小的那个了!再多出去一些,可能对其中有个数来说,就跑到下一个块了
然后好奇了一下,这样改会不会对时间复杂度有影响?
答:没啥头绪,不会想,反正跑得挺快的hhh
标签:GCD,分块,ll,v1,v2,倍数,整除 来源: https://www.cnblogs.com/liyishui2003/p/16391470.html