COCI2022-2023#1 Neboderi

P9032 [COCI2022-2023#1] Neboderi

题目大意

有一个长度为 n n n的序列 h i h_i hi,你需要从中选择一个长度大于等于 k k k的子区间 [ l , r ] [l,r] [l,r],使得 g × ( h l + h l + 1 + ⋯ + h r ) g\times (h_l+h_{l+1}+\cdots+h_r) g×(hl+hl+1+⋯+hr)最小,其中 g = gcd ⁡ ( h l , h l + 1 , ... , h r ) g=\gcd(h_l,h_{l+1},\dots,h_r) g=gcd(hl,hl+1,...,hr)。

1 ≤ k ≤ n ≤ 1 0 6 , 1 ≤ h i ≤ 1 0 6 1\leq k\leq n\leq 10^6,1\leq h_i\leq 10^6 1≤k≤n≤106,1≤hi≤106

题解

当确定了 l l l时, gcd ⁡ ( h l , h l + 1 , ... , h r ) \gcd(h_l,h_{l+1},\dots,h_r) gcd(hl,hl+1,...,hr)随着 r r r的增大而减小。

每当 gcd ⁡ \gcd gcd减小时,其 gcd ⁡ \gcd gcd相对于原来的 gcd ⁡ \gcd gcd肯定有若干个质因数的次数减小。那么,对于一个确定的 l l l, gcd ⁡ ( h l , h l + 1 , ... , h r ) \gcd(h_l,h_{l+1},\dots,h_r) gcd(hl,hl+1,...,hr)的取值不会超过 log ⁡ a l \log a_l logal个数。

先用 S T ST ST表维护区间 gcd ⁡ \gcd gcd。枚举 l l l,在二分每一段 g c d gcd gcd值相等的区间并取该区间的右端点作为 r r r来更新答案。

设 v v v为 a i a_i ai的最大值,则时间复杂度为 O ( n log ⁡ n log ⁡ v ) O(n\log n\log v) O(nlognlogv)。

当然,这是跑不满的,而且时限为 2.50 s 2.50s 2.50s,所以可以过。

code

cpp 复制代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N=1000000;
int n,k,now,v[N+5],lg[N+5],f[N+5][20];
long long ans=0,sum[N+5];
int gcd(int i,int j){
	while(j){
		i%=j;swap(i,j);
	}
	return i;
}
int gt(int l,int r){
	int x=lg[r-l+1];
	return gcd(f[l][x],f[r-(1<<x)+1][x]);
}
int to(int w,int be,int hv){
	int l=be+1,r=n,mid;
	while(l<=r){
		mid=l+r>>1;
		if(gt(w,mid)>=hv) l=mid+1;
		else r=mid-1;
	}
	return l-1;
}
int main()
{
	scanf("%d%d",&n,&k);
	lg[0]=-1;
	for(int i=1;i<=n;i++){
		lg[i]=lg[i/2]+1;
		scanf("%d",&v[i]);
		sum[i]=sum[i-1]+v[i];
		f[i][0]=v[i];
	}
	for(int i=1;i<=19;i++){
		for(int j=1;j<=n-(1<<i-1);j++){
			f[j][i]=gcd(f[j][i-1],f[j+(1<<i-1)][i-1]);
		}
	}
	for(int l=1,r;l<=n-k+1;l++){
		now=gt(l,l+k-1);
		r=to(l,l+k-1,now);
		while(r<=n){
			ans=max(ans,gt(l,r)*(sum[r]-sum[l-1]));
			if(r==n) break;
			now=gt(l,r+1);
			r=to(l,r+1,now);
		}
	}
	printf("%lld",ans);
	return 0;
}
相关推荐
芊寻(嵌入式)4 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
獨枭5 分钟前
C++ 项目中使用 .dll 和 .def 文件的操作指南
c++
霁月风8 分钟前
设计模式——观察者模式
c++·观察者模式·设计模式
橘色的喵9 分钟前
C++编程:避免因编译优化引发的多线程死锁问题
c++·多线程·memory·死锁·内存屏障·内存栅栏·memory barrier
何曾参静谧44 分钟前
「C/C++」C/C++ 之 变量作用域详解
c语言·开发语言·c++
AI街潜水的八角1 小时前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
JSU_曾是此间年少1 小时前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋2 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧3 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
lulu_gh_yu3 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法