[BZOJ]4488: [Jsoi2015]最大公约数 结论暴力

来源:互联网 发布:没有网络的游戏 编辑:程序博客网 时间:2024/06/07 00:02

Description

给定一个长度为 N 的正整数序列Ai对于其任意一个连续的子序列
{Al,Al+1…Ar},我们定义其权值W(L,R )为其长度与序列中所有元素的最大公约数的乘积,即W(L,R) = (R-L+1) ∗ gcd (Al..Ar)。
JYY 希望找出权值最大的子序列。

题解:

结论:固定右端点r,左端点l1~r,最多只有logar个不同的序列最大公因数。因为r~r的最大公因数为ar,而下一个小于它的最大公因数最大为ar2,所以最多只有logar个。知道这个就可以枚举右端点乱搞了。时间复杂度O(Nlog1012)

代码:

#include<bits/stdc++.h>using namespace std;#define LL long longconst int Maxn=100010;LL read(){    LL x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*f;}int n;LL a[Maxn];LL gcd(LL a,LL b){return((b==0)?a:gcd(b,a%b));}struct A{int x;LL g;}f[2][Maxn];bool cmp(A a,A b){return((a.g==b.g)?a.x<b.x:a.g<b.g);}int main(){    LL ans=0;    scanf("%d",&n);    for(int i=1;i<=n;i++)a[i]=read();    int l=0,now=1,last=0;    for(int i=1;i<=n;i++)    {        for(int j=1;j<=l;j++)f[last][j].g=gcd(f[last][j].g,a[i]);        f[last][++l].g=a[i];f[last][l].x=i;        sort(f[last]+1,f[last]+1+l,cmp);        int ll=0;f[last][0].g=-1;        for(int j=1;j<=l;j++)        if(f[last][j-1].g!=f[last][j].g)f[now][++ll]=f[last][j];        for(int j=1;j<=ll;j++)ans=max(ans,(LL)(i-f[now][j].x+1)*f[now][j].g);        l=ll;last^=1;now^=1;    }printf("%lld",ans);}