UPC-魔法序列(结论+枚举)

魔法序列

时间限制: 1 Sec 内存限制: 128 MB
[提交] [状态]
题目描述
小E为了完成公主的任务,需排布魔法阵,从中获得法力。
简单起见,魔法阵可以看成一个长度为n的序列。序列从左到右都摆放了一张符卡,符卡有一个强度ai。法术的释放要每个元素相互配合,取得共鸣效果。一个由一些符卡组成的咒语的魔力值为这个咒语中所有符卡的强度的最大公因数乘以符卡的个数。
小E会从魔法阵中选择一段连续符卡区间[l,r](包括l,r端点),作为吟唱的咒语。她想知道,咒语最大的魔力值是多少。
输入
第一行一个整数n,表示符卡个数。
第二行n个正整数,第i个数表示符卡的强度ai。
输出
输出一个整数,表示最大的魔力值。
样例输入 Copy
5
30 60 20 20 20
样例输出 Copy
80
提示
样例解释
选择区间[2,5],其中gcd(60,20,20,20)=20,故魔力值为(5-2+1)*20=80。
在这里插入图片描述
有一个结论是

区间GCD收敛的很快,gcd的种类最多不超过nlogx(x是数的个数)

找不到证明了……

然后就可以进行优雅的暴力了~

枚举右端点,再每一个右端点内更新并记录gcd的值:记录每一个gcd出现的最靠左的位置,因为相同的gcd和相同的右端点,左端点越靠左,区间长度越长。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
 
const int maxn=1e5+100;
 
ll n,a[maxn];
 
ll gcd(ll a,ll b){
    return b==0?a:gcd(b,a%b);
}
 
map<ll,ll>mp1;
map<ll,ll>mp;
 
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    ll res=0;
    for(int i=1;i<=n;i++){///枚举右端点
        mp=mp1;///用之前的区间更新这次对于右端点来说gcd的值和位置
        mp1.clear();
        res=max(res,a[i]);///区间长度是1
        if(!mp1.count(a[i])) mp1[a[i]]=i;
        for(auto it=mp.begin();it!=mp.end();it++){
            ll tmp=gcd(a[i],it->first);
            res=max(res,tmp*(i-it->second+1));
            
            if(!mp1.count(tmp)) mp1[tmp]=it->second;///记录这次对于下一个右端点的信息
            else mp1[tmp]=min(mp1[tmp],it->second);
            
        }
    }
    cout<<res<<endl;
    return 0;
}

类似的题:HDU5869
好短……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豆沙睡不醒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值