首页 > 其他分享 >LCM Sum[数论+树状数组]

LCM Sum[数论+树状数组]

时间:2023-08-11 10:11:35浏览次数:41  
标签:lcm 200005 树状 int Sum 三元组 ans LCM ll

Problem - E2 - Codeforces

给一个区间[L,R],询问有多少三元组(i,j,k)满足L=<i<j<k<=r且lcm(i,j,k)>=i+j+k.

正难则反。我们可以考虑它的补集。

lcm<i+j+k,然后是i+j+k<3*k

所以lcm<3k,又因为k是lcm的因数,所以lcm=k或者2k。

那么答案变成了求L,R里lcm=k和2k的三元组的数目

如果lcm=k说明i,j都是k的因数,等于2k的手算推出来只有(3,4,6)和(6,10,15)两个及他们的倍数。

总共有(r-l+1)*(r-l)/2*(r-l-1)/3种,减去上述两种即可。

E1的简单版本数据范围小,枚举可以过,E2数据过大,由于我目前还不会CDQ分治,最后选择的树状数组。

要求i∈L,R里Σfac(i),我们可以看成一个前缀和,因为R<=2e5所以完全可以建立一个树状数组。用一个数组处理好(i,k)之间k的因子j的个数(i也是k的因子),就是固定i,k后的坏三元组的数目。按照右端点升序排列(n sqrt(n)数量级)

把查询存起来,按照右端点升序。每次查询之前加入右端点小于等于查询右端点的数,那么此时的前缀和ask(c)就是1-c对1-R里坏三元组的贡献。

最后按照前缀和相减得结果即可

查看代码

#pragma GCC optimize(2)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
struct sq
{
	int l,r,id;
}q[100005];//存储查询
struct poi
{
	int x,y,cnt;
}a[10000005];//存储(x,y)之间y的因子数,也就是固定x,y能组成的坏三元组数
int sz[200005],tot,bit[200005];
ll ans[200005];
vector<int>fac[200005];//存储因子
void pre()
{
	for(int i=1;i<=2e5;i++)
	{
		for(int j=2;j*i<=2e5;j++)
		{
			sz[i*j]++;
			fac[i*j].push_back(i);
		}
	}
	for(int i=1;i<=2e5;i++)
	{
		for(int j=0;j<(ll)fac[i].size()-1;j++)
		{
			a[++tot].x=fac[i][j];
			a[tot].y=i;
			a[tot].cnt=sz[i]-1;//记得不包括x,y所以要-1
			sz[i]--;
		}
	}
	//按照右端点排序
	sort(a+1,a+1+tot,[](poi x,poi y)->bool{return x.y==y.y?x.x<y.x:x.y<y.y;});
}
//下面是树状数组
inline int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int k)
{
	while(x<=2e5)
	{
		bit[x]+=k;
		x+=lowbit(x);
	}
}
ll ask(int x)
{
	ll sum=0;
	while(x>0)
	{
		sum+=bit[x];
		x-=lowbit(x);
	}
	return sum;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	pre();
	int t;
	cin>>t;
	for(int i=1;i<=t;i++)
	{
		cin>>q[i].l>>q[i].r;
		//先算好ans
		ans[i]=1LL*(q[i].r-q[i].l+1)*(q[i].r-q[i].l)/2*(q[i].r-q[i].l-1)/3;
		//处理两种2k的情况
		ans[i]-=max((ll)0,(ll)q[i].r/6-(q[i].l-1)/3);
		ans[i]-=max((ll)0,(ll)q[i].r/15-(q[i].l-1)/6);
		q[i].id=i;
	}
	//将询问也按照右端点排序
	sort(q+1,q+1+t,[](sq x,sq y)->bool{return x.r<y.r;});
	int lt=1;
	for(int i=1;i<=t;i++)
	{
		//把当前对该区间可能有贡献的先加上
		while(a[lt].y<=q[i].r&&lt<=tot)
		{
			//我们之前已经计算了对于固定的右节点,每个左节点的贡献值是多少,
			//累加到对应左节点上,此时左节点的值代表R为q[i].r时,该节点能贡献的坏二元组数
			//那么前缀和就是从1-R的坏二元组数之和了。
			//似乎树状数组经典的按照第二维有序,那么就按照无序的另一维来进行添加
			add(a[lt].x,a[lt].cnt);
			lt++;
		}
		//类似前缀和作差
		ans[q[i].id]-=(ask(q[i].r)-ask(q[i].l-1));
	}
	for(int i=1;i<=t;i++)
		cout<<ans[i]<<'\n';
	return 0;
}

 

标签:lcm,200005,树状,int,Sum,三元组,ans,LCM,ll
From: https://www.cnblogs.com/qbning/p/17622328.html

相关文章

  • 2018牛客多校第五场 F take[树状数组]
    理解题目画了一个二叉树,然后思维定势让我想构建一个有n层的二叉树,然后统计叶子节点。。有点恐怖。但是正解是考虑每一个箱子对答案的贡献。图片来自take_baymax520的博客对于每个箱子,它要发生交换也就是为答案贡献的条件是它当前宝石大小小于它的大小。对于比它小的宝石之前取......
  • 树状数组
    初步感受已知\(a_i\),求\(\sum_{i=1}^7a_i\)。暴力:\(ans=a_1+a_2+a_3+a_4+a_5+a_6+a_7\)时间复杂度:\(O(n)\)树状数组:已知\(A=\sum_{i=1}^4a_i\),\(B=\sum_{i=5}^6a_i\),\(C=\sum_{i=7}^7a_i\),则\(ans=A+B+C\)时间复杂度:\(O(\logn)\)这就是树状数组能快速求解信息的......
  • UESTC 2023 Summer Training #23 for div2/2022-2023 ACM-ICPC Latin American Region
    Preface今天这场签到巨多,和昨天那场形成了鲜明的对比但可惜后盘的时候我划了太久的水,最后接了B题然后没调出来成为战俘最气的是赛后发现原来是没注意输出格式,本来可以说一遍过的题结果没写过,属实可惜,就当长教训了以后一定要尤其注意输入输出格式A.AskingforMoneyORZ徐......
  • 树状数组学习笔记
    树状数组作为一个常数小且好写的数据结构,虽然功能没有线段树那么齐全,但是其中的扩展内容还是很多的。维护区间和1.0BIT的作用树状数组可以做到单次logn求前缀和,单次logn修改信息维护一个前缀和。1.1区间修改单点查询考虑维护差分数组\(c[i]=a[i]-a[i-1]\)。在查询......
  • LeetCode 16. 3Sum Closest 双指针+排序
    Givenanintegerarraynumsoflengthnandanintegertarget,findthreeintegersinnumssuchthatthesumisclosesttotarget.Returnthesumofthethreeintegers.Youmayassumethateachinputwouldhaveexactlyonesolution.Solution先将原数组排序,然......
  • 树状数组
    大佬的讲解视频讲解两者搭配食用效果更佳树状数组就是一个树状数组的板子题intlowbit(intx){returnx&(-x);}求最低位1代表的值是多少voidadd(intx,inty){while(x<=n){c[x]+=y;x+=lowbit(x);}}将包含这个数的每一个值都更新int......
  • php 无限级分类,超级简单的无限级分类,支持输出树状图
    返回一维数组//无限级分类 function GetTree($arr, $pid = 0, $step = 0){    static $tree;    foreach ($arr as $key => $val) {        if ($val['pid'] == $pid) {            $name = isset($val['title']) ? $......
  • Calculate floor sum
    problem不用ACL!llfs(lln,llm,lla,llb){ llres=0; if(a>=m){ res+=n*(n+1)/2*(a/m),a%=m; } if(b>=m){ res+=(n+1)*(b/m),b%=m; } llc=(a*n+b)/m; if(!c){ returnres; } res+=n*c-fs(c-1,a,m,m-b-1); returnres;}......
  • 【JAVA8】快速理解Consumer、Supplier、Predicate与Function
                 快速理解Consumer、Supplier、Predicate与Function一、前言这几个接口都处在java.util.function包下,Consumer(消费型),Supplier(供给型)、Predicate(判断型)与Function(转换型),暂时不理解他们的类型没关系。如果对Lambda不怎么理解的同学,可以......
  • ORSum
    ABC291GORSum题意:有两个长度为\(N\)的序列\(A,B\),可以给\(A\)序列向左循环移动若干位,求\(\sum(A_i|B_i)\)的最大值。\(N\le5\times10^5\)而\(0\leA_i,B_i\le31\)。题解:发现or操作有点点困难,那么我们就把两个序列取反,然后求and的最小值。尝试形式化枚举每个......