[LUOGU]P5502 [JSOI2015]最大公约数

传送门

题意:给一个序列a[1],a[2],a[3]...a[n],求其中连续的子序列A[L],A[L+1],...,A[R],使其权值 W(L,R)=(R-L+1)×gcd(A[L],...,A[R])最大。

思路:

简单的一个分治思想。

先想想线段树里询问怎么做的?

是不是把这个区间从中间砍开。然后丢到左/右儿子那里再问。

同样的,在这里,对于所要求的ans区间

也是可以 劈开 讨论的

·ans区间全在当前区间(l,r) 的右侧(l,mid);

·ans区间全在当前区间(l,r) 的左侧(mid+1,r);

·ans区间横跨左右儿子;

对前俩种,直接往下递归就行。

第三种,枚举一遍整个(l,r)区间,找到含有a[mid]的最大权值区间就行。此处复杂度约O(n).

p.s.第三种情况可以从mid开始向两边拓展。

 


 

OVER.

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define re register
 4 #define LL long long
 5 #define DB double
 6 #define For(x,a,b) for(re int x=a;x<=b;x++)
 7 #define For2(x,a,b) for(re int x=a;x>=b;x--)
 8 #define LFor(x,a,b) for(re LL x=a;x<=b;x++)
 9 #define LFor2(x,a,b) for(re LL x=a;x>=b;x--)
10 #define Abs(x) ((x>0)? x:-x)
11 int gi()
12 {
13     int res=0,fh=1;char ch=getchar();
14     while((ch>'9'||ch<'0')&&ch!='-') ch=getchar();
15     if(ch=='-') fh=-1,ch=getchar();
16     while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
17     return fh*res;
18 }
19 LL gl()
20 {
21     LL res=0,fh=1;char ch=getchar();
22     while((ch>'9'||ch<'0')&&ch!='-') ch=getchar();
23     if(ch=='-') fh=-1,ch=getchar();
24     while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
25     return fh*res;
26 }
27 int n;
28 LL a[100005],ans;
29 LL gcd(LL x,LL y) {return y==0? x:gcd(y,x%y);}
30 LL deal(int l,int r,int L,int R)
31 {
32     LL _gcd=a[l],val=a[l],f=l;
33     while(L<l&&r<R)
34     {
35         _gcd=gcd(_gcd,a[l-1]);
36         l--;
37         while(r<=R&&a[r]%_gcd==0) r++;
38         while(L<=l&&a[l]%_gcd==0) l--;
39         val=val<(LL)(r-l-1)*_gcd? (LL)(r-l-1)*_gcd:val;
40         l++,r--;
41     }
42     l=r=f;
43     _gcd=a[r];
44     while(L<l&&r<R)
45     {
46         _gcd=gcd(_gcd,a[r+1]);
47         r++;
48         while(L<=l&&a[l]%_gcd==0) l--;
49         while(r<=R&&a[r]%_gcd==0) r++;
50         val=val<(LL)(r-l-1)*_gcd? (LL)(r-l-1)*_gcd:val;
51         l++,r--;
52     }
53     return val;
54 }
55 LL dfs(int l,int r)
56 {
57     if(l==r) return a[l];
58     int mid=l+r>>1;
59     LL opt1=deal(mid,mid,l,r);
60     LL opt2=dfs(l,mid);
61     LL opt3=dfs(mid+1,r);
62     return max(opt1,max(opt2,opt3));
63 }
64 
65 int main()
66 {
67     n=gi();
68     For(i,1,n) a[i]=gl();
69     printf("%lld\n",dfs(1,n));
70     return 0;
71 }
View Code

 

转载于:https://www.cnblogs.com/3soon/p/11536234.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值