【题解】最大公约数

题面

题目背景

寻求最大公约数是人民*的真谛。

题目描述

小 L 极其喜爱 gcd ⁡ \gcd gcd。

有一天,小 Z :小 L,问你个题。

小 Z:给出一个长度为 n n n 的序列 a a a 和一个整数 k k k ,把这个序列划分成连续的 k k k 段,每一段不能为空。

小 L:等等, gcd ⁡ \gcd gcd 去哪里了。

小 Z:别急嘛,我们设 b i b_i bi​ 表示第 i i i 段的最大值,请问怎么划分该序列使得 gcd ⁡ ( b 1 , b 2 , . . . , b k ) \gcd(b_1,b_2,...,b_k) gcd(b1​,b2​,...,bk​) 的值最大。

小 L 沉思了一会,发现自己不会做,彻底地自闭了,于是他又向你来求助了,请你帮帮他。

输入格式

输入文件名为 gcd.in

输入文件第一行包含两个整数 n n n , k k k,表示序列的长度和需要划分的段数。

接下来第二行包含 n n n 个整数,表示这个序列。

输出格式

输出文件名为 gcd.out

输出文件包含一个整数,表示你的答案。

样例

样例输入 1

5 3
1 3 2 9 6

样例输出 1

3

样例解释 1

最优的划分可能有多种,这里给出一种最优的划分,将序列分成 [ 1 , 3 ] [1,3] [1,3] , [ 2 , 9 ] [2,9] [2,9] , [ 6 ] [6] [6] 三段,其中 b 1 = 3 b_1=3 b1​=3 , b 2 = 9 b_2=9 b2​=9 , b 3 = 6 b_3=6 b3​=6,所以答案为 gcd ⁡ ( 3 , 9 , 6 ) = 3 \gcd(3,9,6)=3 gcd(3,9,6)=3 。

数据规模与约定

对于 100 % 100\% 100% 的数据, 1 ⩽ k ⩽ n ⩽ 1 0 3 1\leqslant k\leqslant n\leqslant 10^3 1⩽k⩽n⩽103 , 1 ⩽ k ⩽ 5 × 1 0 2 1\leqslant k \leqslant 5\times 10^2 1⩽k⩽5×102 , 1 ⩽ a i ⩽ 1 0 6 1\leqslant a_i\leqslant 10^6 1⩽ai​⩽106。

Solution

出题人米巴米巴吃多了,一上来就给一道数论?

彻底自闭的是我才对吧。。。【欲哭无泪.gif】

看起来。。。貌似是道。。。DP?[凭感觉做题晚期患者再次上线]


每个分段的最大值里面,一定会有整个序列的最大值,也就是说,最终求到的 gcd ⁡ \gcd gcd ,一定是最大值的因数。

因为分组未知的情况下,只能求得整个序列的最大值,我们以此为突破口。

设最大值为 m x mx mx .

枚举 m x mx mx 的每个因数为最大公约数的情况, d i v i i divi_i divii​ 表示 m x mx mx 从 1 1 1 开始的第 i i i 个因数。

那么,我们已经(其实是我)想象到了这可能是一道DP,那么状态呢?

对于 divi[i] , dp[j] 表示前 j 个数可以分成的最大段数,并且每一段的最大值都是 divi[i] 的倍数

状态转移方程的柿子呢?

设 mxx 为 a[k]~a[j](k<=j) 的最大值
如果 divi[i] 整除 mxx:
	dp[j]=max(dp[j],dp[k-1]+1);

为什么?

既然 m x x mxx mxx 是当前的最大值,并且 m x x mxx mxx 也是 d i v i i divi_i divii​ 的倍数,那么 m x x mxx mxx 就可以作为当前分段的最大值。

而我们要保证可以分的段数最大,我们想, m x x mxx mxx 表示的是 a k a_k ak​ ~ a j a_j aj​ 的最大值,那么,我们就将 a k a_k ak​ ~ a j a_j aj​ 分为一段不就行了?

而分到这里最大的段数就是分到 a k − 1 a_{k-1} ak−1​ 时的最大段数加上当前段的 1 1 1 。


如果对于 d i v i [ i ] divi[i] divi[i], d p n dp_n dpn​ 可以分的段数 ⩾ k \geqslant k ⩾k,因为 d i v i i divi_i divii​ 是从小到大排列的,最新的一定是最大的,我们直接更新答案。


初始化时,因为要求最大值,初始化成 − 0 x 3 f 3 f 3 f 3 f -0x3f3f3f3f −0x3f3f3f3f , d p 0 = 0 dp_0=0 dp0​=0 。


Code

#include<cstdio>
#include<cstring>
const int maxn=1e3+5;
int a[maxn];
int dp[maxn];
int divi[maxn];
int n,k,mx,tot,ans;
int max(int x,int y){
	return x>y?x:y;
}
void read(int&x){
	x=0;
	bool f=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		x=x*10+(ch&15);
		ch=getchar();
	}
	if(f)x=-x;
	return;
}
int main(){
	read(n);read(k);
	for(int i=1;i<=n;++i){
		read(a[i]);
		mx=max(mx,a[i]);
	}
	for(int i=1;i<=mx;++i){
		if(mx%i==0)
			divi[++tot]=i;
	}
	for(int i=1;i<=tot;++i){
		memset(dp,-0x3f3f3f3f,sizeof(dp));
		dp[0]=0;
		for(int j=1;j<=n;++j){
			int mxx=-0x3f3f3f3f;
			for(int k=j;k;--k){
				mxx=max(mxx,a[k]);
				if(mxx%divi[i]==0)
					dp[j]=max(dp[j],dp[k-1]+1);
			}
		}
		if(dp[n]>=k)ans=divi[i];
	}
	printf("%d",ans);
	return 0;
}

end.

上一篇:Python json问题整理


下一篇:csps-模拟7778lrd两试