BZOJ 4488:[Jsoi2015]最大公约数 UPC:2018山东冬令营 权值 (GCD)

时间限制: 1 Sec  内存限制: 512 MB
提交: 57  解决: 19
[提交][状态][讨论版][命题人:admin]

题目描述

给定一个长为n的正整数序列Ai。对于它的任意一个连续的子序列{Al, Al+1, ..., Ar},定义其权值W (l, r)为其长度与序列中所有元素的最大公约数的乘积,即W (l, r)  = (r − l + 1) × gcd(Al, Al+1, .., Ar )。
你需要输出权值最大的子序列的权值

输入

第一行一个正整数n。
第二行n个正整数,表示序列Ai。

输出

一行一个正整数,表示答案。

样例输入

5

30 60 20 20 20

样例输出

80

提示

最后四个元素形成的子序列权值最大。

对于前30%的数据:n ≤ 2000
对于所有数据:1 ≤ n ≤ 105,1 ≤ Ai ≤ 109

来源


【思路】

    有一个定理  :    长度为n的子序列中  , GCD 最多为log(n)  

    在 BZOJ 上 这个 时间限度时 10s 在 upc 上 限定1s  ;  

    很尬尬的用 Map 数组,  在bzoj上跑1s  在  upc 上 跑1092ms  差一丢丢  就是过不去;

    改用数组标记 时间 降到128ms  ,  说明UPC 对 STL 库 的支持 不是很好哇;

    固定右端点(枚举右端点)     去掉重复的 gcd ,  延伸最左端点能达到最长;

    map 的话 不断翻滚,  数组  是去重


【代码实现】

STL map的‘

#include <iostream>
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll INF=0x3f3f3f3f;
const int MAXN=1e5+5;
const int MOD=1e9+7;
 
using namespace std;
 
inline ll gcd(ll a,ll b) { return b? gcd(b,a%b):a;}
 
ll a[MAXN];
 
map<ll,ll>mp,tmp;
map<ll,ll>::iterator it;
int main()
{
    int n;
    ll ans=-INF;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,a[i]);
        for(it=mp.begin();it!=mp.end();it++)
        {
            ll now_gcd = gcd(it->first,a[i]);
            ans= max(ans, now_gcd*(i-it->second+1));
            if(!tmp[now_gcd])
                tmp[now_gcd]=(it->second);
            else
                tmp[now_gcd]= min(tmp[now_gcd],it->second); // 取left最远
        }
        if(!tmp[a[i]])
            tmp[a[i]]=i;
        mp=tmp;
        tmp.clear();
    }
    printf("%lld",ans);
    return 0;
}


用数组标记的  128ms 

#include <iostream>
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll INF=0x3f3f3f3f;
const int MAXN=1e5+5;
const int MOD=1e9+7;
 
using namespace std;
 
inline ll gcd(ll a,ll b) { return b? gcd(b,a%b):a;}
 
ll col[MAXN];
ll gc[MAXN];
ll a[MAXN];
map<ll,ll>mp,tmp;
map<ll,ll>::iterator it;
int main()
{
    int n;
    ll ans=-INF;
    int k=0,cot;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)
    {
        col[++k]=i;
        gc[k]=a[i];
 
        for(int j=k-1;j>=1;j--)
            gc[j]=gcd(gc[j],gc[j+1]);
 
        int cot=0;
        for(int j=1;j<=k;)
        {
            gc[++cot]=gc[j];
            col[cot]=col[j];
            while(gc[cot]==gc[j]) j++;
        }
        k=cot;
        for(int j=1;j<=k;j++)
        {
            ans=max(ans,gc[j]*(i-col[j]+1));
        }
    }
    printf("%lld",ans);
    return 0;
}

123

posted @ 2018-03-20 13:45  Sizaif  阅读(168)  评论(0编辑  收藏  举报