luogu P5502 [JSOI2015]最大公约数

背景:

刷的水题越来越多了。

题目传送门:

https://www.luogu.org/problem/P5502

题意:

定义区间 [ l , r ] [l,r] [l,r]的贡献为 ( r − l + 1 ) ⋅ gcd ⁡ ( a l , a l + 1 , . . . , a r ) (r-l+1)\cdot \gcd(a_l,a_{l+1},...,a_{r}) (rl+1)gcd(al,al+1,...,ar)。求最大贡献。

思路:

容易想到这些数的 gcd ⁡ \gcd gcd个数不会很多,据说是 Θ ( log ⁡ 值 域 ) \Theta(\log值域) Θ(log)级别的。
考虑确定了右端点 x x x,我们之前已经得到了 x − 1 x-1 x1 gcd ⁡ \gcd gcd后缀,那么我们就可以将 x x x位置的贡献与这 x − 1 x-1 x1个贡献计算一下,或者在 x x x位置作为起点,新开一个后缀,起点从 x x x开始。
然后考虑 gcd ⁡ \gcd gcd相同的数,我们只要起点尽可能靠前的哪一个即可,其余都是废的,排个序即可。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define LL long long
#define INF (LL)1e9
using namespace std;
map<LL,bool> MAP;
	int n;
	LL ans=0;
	LL a[100010];
	struct node{LL x;int op;} b[100010];
LL gcd(LL x,LL y)
{
	return !y?x:gcd(y,x%y);
}
bool cmp(node x,node y)
{
	return x.op<y.op;
}
int main()
{
	scanf("%d",&n);
	ans=n;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		ans=max(ans,a[i]);
	}	
	int t=0;
	for(int i=1;i<=n;i++)
	{
		b[++t]=(node){a[i],i};
		for(int j=1;j<=t;j++)
		{
			b[j].x=gcd(b[j].x,a[i]);
			ans=max(ans,b[j].x*(i-b[j].op+1));
		}
		MAP.clear();
		for(int j=1;j<=t;j++)
			if(b[j].x==1||MAP[b[j].x]) b[j]=(node){0,INF}; else MAP[b[j].x]=true;
		sort(b+1,b+t+1,cmp);
		while(t&&b[t].op==INF) t--;
	}
	printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值