【洛谷】P7009 [CERC2013] Magical GCD
题意
有 组询问,每次给出 个数 。
你需要找到这个数组的一个子序列(要求编号连续),使得该序列中所有数的最大公约数和序列长度的乘积最大,并输出这个最大值。
数据范围
。
思路
参考了这篇博客。
对于原序列的一个子区间,如果固左端点 不断往右延伸,设当前区间的最大公约数为 ,现在要把元素 扩展进来,新区间的最大公约数要么还是 ,要么就至少减少一半(根据 的性质),那么区间的 就至多更新 。
因为题目所求的是最大值,那么对于 相同的区间,肯定会选择长度最长的区间。那么就可以从前往后枚举 ,用一个队列 记录这些不同的左端点,同时用 去更新这些左端点,并同时更新答案。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
#define LL long long
queue<int>q,r;
int n;LL a[N],res;
LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d",&n);res=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);LL last=0;res=max(res,a[i]);
while(!q.empty())
{
int x=q.front();q.pop();a[x]=gcd(a[x],a[i]);//x就是最小的满足区间[x,i]的gcd为a[x]的左端点
res=max(res,a[x]*(i-x+1));
if(a[x]==a[last]) continue;//一些左端点就可以合并掉
r.push(x);last=x;
}
while(!r.empty())
{
q.push(r.front());
r.pop();
}
if(a[last]!=a[i]) q.push(i);//i也可以作为一个新的左端点
}
printf("%lld\n",res);
while(!q.empty()) q.pop();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话