博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[题解]第十一届北航程序设计竞赛预赛——D.最大公约数
阅读量:7107 次
发布时间:2019-06-28

本文共 2725 字,大约阅读时间需要 9 分钟。

题目描述

给一个长度为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 
2 #include
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 else48 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 else65 {66 tmp = a[i];67 flag = true;68 }69 }70 else71 {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 }
View Code

 

另一种思路

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

最大公约数满足结合律,所以题目所说相等的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

转载于:https://www.cnblogs.com/CQBZOIer-zyy/p/5047001.html

你可能感兴趣的文章
转载 WebBrowser介绍——Javascript与C++互操作
查看>>
使用MAVEN打JAR,直接使用
查看>>
给电信专业大二学生解答几个问题
查看>>
libguestfs手册(1): 架构
查看>>
iTextSharp快速使用指南
查看>>
C语言(1+1+2+1+2+3....+n)
查看>>
浅谈 js 字符串 search 方法
查看>>
css调整图片位置布局
查看>>
华为的JAVA面试题及答案(部分)
查看>>
定时关机命令——shutdown
查看>>
基于Java的数据采集(三)
查看>>
【编程题目】最长公共字串
查看>>
lucene 专业名词作用整理
查看>>
win32 自定义右键菜单
查看>>
Cocos2d-x3.0TestCpp文件夹笔记(二)
查看>>
CentOS-6.5安装配置Tengine
查看>>
机器视觉之 ICP算法和RANSAC算法
查看>>
为什么GOF的23种设计模式里面没有MVC?
查看>>
[WebGL入门]十,矩阵计算和外部库
查看>>
SQL 存储过程(转帖摘录)
查看>>