LCM Sum (hard version)(树状数组,筛因子)

目录

思路:

代码:


 

LCM Sum (hard version)

This version of the problem differs from the previous one only in the constraint on tt. You can make hacks only if both versions of the problem are solved.

You are given two positive integers ll and rr.

Count the number of distinct triplets of integers (i,j,k)(i,j,k) such that l≤i<j<k≤rl≤i<j<k≤r and lcm(i,j,k)≥i+j+klcm⁡(i,j,k)≥i+j+k.

Here lcm(i,j,k)lcm⁡(i,j,k) denotes the least common multiple (LCM) of integers ii, jj, and kk.

Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1051≤t≤105). Description of the test cases follows.

The only line for each test case contains two integers ll and rr (1≤l≤r≤2⋅1051≤l≤r≤2⋅105, l+2≤rl+2≤r).

Output

For each test case print one integer — the number of suitable triplets.

Example

input

Copy

 

5

1 4

3 5

8 86

68 86

6 86868

output

Copy

3
1
78975
969
109229059713337

Note

In the first test case, there are 33 suitable triplets:

  • (1,2,3)(1,2,3),
  • (1,3,4)(1,3,4),
  • (2,3,4)(2,3,4).

In the second test case, there is 11 suitable triplet:

  • (3,4,5)(3,4,5).

思路:

正难则反

1,讨论总的情况:(r-l+1)*(r-l-1)/6

2,讨论lcm的情况:lcm(i,j,k)<i+j+k,lcm<=k-2+k-1+k=>lcm<3*k,=>lcm为k或者2*k

3,讨论i,j的情况:

当lcm为2*k时:

1)k/2<j<k,j=2*k/t=>2<t<4=>t=3=>j=2/3*k

2)2*k<i+j+k=>k<i+j=>k/3<i<k,i=2*k/t=>2<t<6,i<j=>i=k/2||k*2/5

当lcm为k时:

i<j,i和j为k的因子

4,树状数组记载每个数作为i的可行情况数

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define vec vector<int>
#define pii pair<int,int>
#define pi 3.1415926
#define rep(i,l,r) for(int i=l;i<=r;++i)
#pragma GCC optimize(2)//
#pragma GCC optimize(3,"Ofast","inline")//
const int maxj=2e5+10,mod=1e9+7,inf=0x3f3f3f3f;
struct bit{
    int sum[maxj];
    int lowbit(int x){return x&-x;}
    void add(int x,int c){while(x<=maxj)sum[x]+=c,x+=lowbit(x);}
    int getsum(int x){int res=0;while(x)res+=sum[x],x-=lowbit(x);return res;}

}tree;
vector<pii>a[maxj];
int ans[maxj];
vec fac[maxj];//存因子
void solve(){
    int n;cin>>n;
    for(int i=1;i<maxj;++i){//存因子
        for(int j=i*2;j<maxj;j+=i){
            fac[j].emplace_back(i);
        }
    }

    for(int i=1;i<=n;++i){//
        int l,r;cin>>l>>r;
        a[r].push_back({l,i});//存数组,l,r
        int x=r-l+1;
        ans[i]=x*(x-1)*(x-2)/6;//正难则反
    }

    for(int r=1;r<maxj;++r){//既是k,又是r,暴力得出答案
        //公因子2*k,找r以内的因子
        for(int j=0;j<fac[r].size();++j){
            int x=fac[r][j];
            int cnt=0;//计数器
            for(int k=j+1;k<fac[r].size();++k){
                int y=fac[r][k];
                if(r%x==0&&r%y==0){
                    cnt+=1;
                }
            }
            tree.add(x,cnt);
        }
        //j为2/3*k
        //i是k/2
        if(r%6==0){
            tree.add(r/2,1);
        }
        //i是2/5*k
        if(r%15==0){
            tree.add(r*2/5,1);
        }
        for(auto i:a[r]){//计算(l,r-2),
            ans[i.second]-=(tree.getsum(r-2)-tree.getsum(i.first-1));
        }
    }
    for(int i=1;i<=n;++i){
        cout<<ans[i]<<'\n';
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);//与快读冲突
    int t;
    t=1;
    // cin>>t;
    while(t--)solve();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值