> 文章列表 > [PTA] 连续因子(C++,数学)

[PTA] 连续因子(C++,数学)

[PTA] 连续因子(C++,数学)

一个正整数 NNN因子中可能存在若干连续的数字。例如 630630630 可以分解为 3×5×6×73×5×6×73×5×6×7,其中 555666777 就是 333 个连续的数字。给定任一正整数 NNN,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列

输入格式:

输入在一行中给出一个正整数 NNN1<N<2311<N<2^{31}1<N<231)。

输出格式:

首先在第 111 行输出最长连续因子的个数;然后在第 222 行中按 因子1*因子2*……*因子k 的格式输出最小的连续因子序列,其中因子按递增顺序输出,111 不算在内。

输入样例:

630

输出样例:

3
5*6*7

解题思路:

想要找出最长的连续因子序列,自然要找出所有的连续因子序列

大致上的思路就是:

(1)先找到一个因子,以此作为起始

(2)接下来不断乘法操作,直到乘积不符合条件

(3)记录结尾数字,找到一个连续因子序列,回到步骤(1)

可行性证明:

如果一个numnumnum能够分解的最长连续因子序列为n1,n2,...,nmn_1,n_2,...,n_mn1,n2,...,nm,那么必然存在k=numn1∗n2∗...∗nmk=\\frac{num}{n_1*n_2*...*n_m}k=n1n2...nmnum,使得num=n1∗n2∗...∗nm∗knum=n_1*n_2*...*n_m*knum=n1n2...nmk

所以找到的连续因子序列符合题意

代码实现如下

for (i = 2; i * i <= num; i++) {if (num % i == 0) {//(1) search for next beginsum = 1;for (j = i; j * sum <= num; j++) {//(2) extend lensum *= j;if (num % sum == 0 && j - i + 1 > max_len) {//(3) updatemax_beg = i;max_len = j - i + 1;}}}
}

由于数据范围是111~2312^{31}231,直接枚举必然TLETLETLE

所以利用因子一定成对出现的性质,我们只枚举到231\\sqrt{2^{31}}231为止

for (i = 2; i * i <= num; i++) {...
}

可行性证明:

对于一个numnumnum,如果在num\\sqrt{num}num之前我们找到的最长连续因子序列长度为lenlenlen

那么在num\\sqrt{num}num之后一定也存在长度为lenlenlen的连续因子序列

但是由于num\\sqrt{num}num之后的任意两个数字乘积≥num\\ge numnum,所以不符合题意

综上所述,最长连续因子序列一定在num\\sqrt{num}num之前出现

最后,AC代码如下

#include <stdio.h>
#include <stdlib.h>
const int max_num = 1 << 31 - 1;int main() {int num;scanf("%d", &num);int max_len = 0, max_beg = -1;long long sum, i, j;for (i = 2; i * i <= num; i++) {if (num % i == 0) {//(1) search for next beginsum = 1;for (j = i; j * sum <= num; j++) {//(2) extend lensum *= j;if (num % sum == 0 && j - i + 1 > max_len) {//(3) updatemax_beg = i;max_len = j - i + 1;}}}}if (max_beg == -1) {max_beg = num;max_len = 1;}printf("%d\\n", max_len);int max_end = max_beg + max_len;for (i = max_beg; i < max_end; i++) {if (i == max_beg) printf("%lld", i);else printf("*%lld", i);}printf("\\n");return 0;
}

注意要开long long,否则循环部分会因为爆精度无法停止,导致TLETLETLE