题目描述

给一个长度为n(1<=n<=100000)的正整数列,分成尽量多的非空段,使得每一段的最大公约数相等。一个数的最大公约数是它本身。

解题思路

要求每一段子列的gcd相等,不妨设为d,可以知道d是所有数的最大公约数,即d=(a[1],a[2],……,a[n])。于是我们先求出d,然后从前往后扫描,记st=1,移动ed,计算d1=(a[st],……,s[ed]),直到d1==d,得到的区间[st,ed]就是一个符合题目要求的子列;记st=ed+1,重复上述操作,直至数列扫完。算法时间复杂度为O(n logx),其中x表示数列的数的大小。

注:

1、由于gcd(a[i],……,a[j])=gcd(gcd(a[i],……,a[k]),gcd(a[k+1],……,a[j])),(i<k<j),所以计算多个数的gcd直接两两计算即可;计算子列的gcd直接在扫描时每多一个书就多一次求gcd即可。

2、按照上述算法可能出现最后一段的gcd不等于d的情况,可以看作最后一段不被单独分出来,而是跟前一段合并为一段的。注意到跟前面的一段合并后gcd一定等于d,因为d=(a[1],a[2],……,a[n]),最后一段的gcd记为ds只能是d的倍数,而前一段的gcd为d,所以合并后gcd一定为d。另外,所谓“前一段”是一定存在的,否则所有的最大公约数不可能为d。

附:c++代码

 1 #include <iostream>
2 #include <cstdio>
3
4 using namespace std;
5 #define MaxN 100020
6
7 int a[MaxN];
8
9 inline void Get_int(int &Ret)
10 {
11 char ch;
12 bool flag=false;
13 for(;ch=getchar(),ch<'0'||ch>'9';)
14 if(ch=='-')
15 flag=true;
16 for(Ret=ch-'0';ch=getchar(),ch>='0'&&ch<='9';Ret=Ret*10+ch-'0');
17 flag&&(Ret=-Ret);
18 }
19
20 inline int My_gcd(int a, int b)
21 {
22 int r;
23 if(a < b)
24 swap(a, b);
25 while(b)
26 {
27 r = a % b;
28 a = b;
29 b = r;
30 }
31 return a;
32 }
33
34 int main ()
35 {
36 int n, ans;
37 int x, tmp;
38 int i;
39 bool flag;
40 while(scanf("%d", &n) != EOF)
41 {
42 for(i = 1; i <= n; i++)
43 {
44 Get_int(a[i]);
45 if(i == 1)
46 x = a[i];
47 else
48 x = My_gcd(a[i], x);
49 }
50 if(n == 1)
51 {
52 printf("1\n");
53 continue;
54 }
55 //printf("%d\n", x);
56 ans = 0;
57 flag = false;
58 for(i = 1; i <= n; i++)
59 {
60 if(!flag)
61 {
62 if(a[i] == x)
63 ans++;
64 else
65 {
66 tmp = a[i];
67 flag = true;
68 }
69 }
70 else
71 {
72 tmp = My_gcd(a[i], tmp);
73 if(tmp == x)
74 {
75 flag = false;
76 ans++;
77 }
78 }
79 }
80 printf("%d\n", ans);
81 }
82 return 0;
83 }

另一种思路

这是官方给出的题解,动归

最大公约数满足结合律,所以题目所说相等的gcd就是原数列的gcd,不妨设为d。

设f[i]为前i个数能分的最大段数,枚举最后一个段是[j+1,i],则有gcdik=j+1ak=d,而f[i]=maxf[j]+1。如果j不存在,可以认为f[i]是不合法的部分,令f[i]=0即可。

不难证明满足条件的j是一段前缀区间,而且f[i]是单调的,所以最大的f[j]一定是尽量靠右的,可以直接找到这个j来对f[i]更新答案。

区间gcd可以预处理ST表得到,或者顺着推以每个点结尾的区间gcd即可,可以证明以每个点结尾的区间gcd的值个数是不超过logn个的,所以整体的复杂度是O(n(logn)^2)。

题目链接:https://biancheng.love/contest-ng/index.html#/29/problems

最新文章

  1. Wireshark工控协议
  2. SQLLDR 教程
  3. http协议(四)http状态码
  4. git 简明使用手册
  5. .Net开源工作流Roadflow的使用与集成(转)
  6. 第六届蓝桥杯B组C++试题
  7. 树莓派/RaspberryPi 内核编译
  8. C# String 与 byte 互转
  9. PAT (Advanced Level) 1007. Maximum Subsequence Sum (25)
  10. 关于MATLAB处理大数据坐标文件201761
  11. chrome使用技巧整理
  12. I/O多路转接之poll 函数
  13. 移动APP及游戏推广,有预算为什么还起不了量
  14. Spring整合ActiveMq消息队列
  15. 转---30 分钟学会 Flex 布局
  16. 鼠标悬浮控制元素隐藏与显示 - css中鼠标的hover状态
  17. PAT甲1077 Kuchiguse【字符串】【暴力】【Hash】【二分】
  18. http &amp; https &amp; http2.0
  19. selenium学习笔记(加入unittest)
  20. Linux mmap 要主动释放共享内存

热门文章

  1. leetcode 33. 搜索旋转排序数组 及 81. 搜索旋转排序数组 II
  2. 高度塌陷与 BFC
  3. gorm连接mysql和模型定义那些事
  4. (2)puppet单机测试命令apply
  5. 不难懂-----Mock基本使用
  6. 在build中配置resources, 来防止我们资源导出失败问题
  7. 云原生新时代弄潮儿k8s凭什么在容器化方面独树一帜?
  8. 使用du与df命令查看磁盘容量不一致
  9. C++ POD 类型
  10. Ubuntu 18.04 安装教程