1. 程式人生 > >【BZOJ4052】[Cerc2013]Magical GCD 亂搞

【BZOJ4052】[Cerc2013]Magical GCD 亂搞

cnblogs cpp name 直接 bzoj4052 scrip des ons ostream

【BZOJ4052】[Cerc2013]Magical GCD

Description

給出一個長度在 100 000 以內的正整數序列,大小不超過 10^12。 求一個連續子序列,使得在所有的連續子序列中,它們的GCD值乘以它們的長度最大。

Sample Input

1
5
30 60 20 20 20

Sample Output

80

題解:先思考暴力的做法。我們從一個數開始往左掃,將所有使得gcd改變的位置都記錄下來。由於gcd的每次改變都至少/2,所以這樣的位置不超過log個。

那麽我們直接從左往右掃,暴力維護所有使得gcd改變的位置即可。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,m,k;
ll ans;
struct node
{
	int x;
	ll g;
}p[maxn],q[maxn];
ll gcd(ll a,ll b)
{
	return (!b)?a:gcd(b,a%b);
}
inline ll rd()
{
	ll ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void work()
{
	n=rd(),ans=0;
	int i,j;
	ll v;
	m=0;
	for(i=1;i<=n;i++)
	{
		v=rd();
		for(j=1;j<=m;j++)	p[j].g=gcd(p[j].g,v);
		p[++m].g=v,p[m].x=i;
		for(k=0,j=1;j<=m;j++)	if(p[j].g>p[j-1].g)	q[++k]=p[j];
		for(j=1;j<=k;j++)	p[j]=q[j],ans=max(ans,(i-p[j].x+1)*p[j].g);
		m=k;
	}
	printf("%lld\n",ans);
}
int main()
{
	int T=rd();
	while(T--)	work();
	return 0;
}

【BZOJ4052】[Cerc2013]Magical GCD 亂搞