编程语言
首页 > 编程语言> > 陕西省第九届大学生程序设计竞赛 C.GCD 整除分块

陕西省第九届大学生程序设计竞赛 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