最长不互质序列————代码与详解
【题目】
现在有一个长度为n的序列,你需要从中选出一些数来,保持这些数在原来序列的相对位置组成一个新的序列,使得相邻的两个元素不互质。输出新序列的最长长度。
两个数不互质,满足它们的最大公约数大于1。
第一行,一个整数n,表示原序列的长度。
第二行,n个数,表示序列中的元素。
输出新序列的最长长度,数据保证答案至少为2。
7
2 3 4 5 6 7 8
4
对于20%的数据,所有输入数据的范围[1,20];
对于40%的数据,所有输入数据的范围[1,10^3];
对于70%的数据,所有输入数据的范围[1,10^5];
对于100%的数据,所有输入数据的范围[1,10^6];
解析:这道题看上去简单,其实隐藏着很多条件,他并不是两两不互质,而是只是相邻(2 6 3这组数据很好说明(答案是3,2、6不互质,6和3不互质)),这就是这道题的精华之处。对于一下子没有头绪的题目,我们根据数据范围来分析这题的算法,很显然,对于20%的数据根本是水过(暴力也行嘛,虽说我测的时候只有10%【打脸ing】),40%对于纯粹的大暴力肯定过不了(O(N4)或更大(一般只能有O(N5)的,优化一下O(N4))),根据题意,不互质就是两个数有公约数,这里找不等于一的公约数(首选GCD,简单又方便),所以不难理解出动态规划算法之解LIS(之所以用,是因为它是一个快速找规定序列的能力的模板)+GCD的简易算法,转移方程是
If (gcd(a[j],a[i])<>1) and (f[j]+1>f[i]) then f[i]:=f[j]+1;(不会的好好看看白书)
想要达到70分,可以说是异(fang)常(qi)困(zhi)难(liao),不过仔细抓住条件尾巴:不互质,学过数学的(敢问在下有没学过的吗)可以想到互质的亲戚:分解质因数,查找质因数,归类,好像挺有道理,我们拿2 3 4 5 6试一下
2 |
3 |
4 |
5 |
6 |
(f[i])2 |
3 |
2 |
5 |
2、3 |
于是有质因子2的数有:2、4、6,共3个
质因子3的数有:3、6,共两个
其它各有一个。
所以最长序列为:2、4、6(完全正确,开心)
再试下之前提到的“上天序列”:2、6、3
2 |
6 |
3 |
(f[i])2 |
2、3 |
3 |
于是有质因子2的有2、6,共两个
质因子3的有6、3,共两个
不难发现,2、6与6、3共有一个6(顺序有关系的),合并2、3单元格,把序列精简为2、6、3,共三个。(又对了,啦啦啦)
不过回头再算一下时间复杂度,外层n,内层质因子分解n*√n(注意要两个分解,第一个就是分解,第二个确定答案数组f[]赋值,优化加一个break(几乎是n*√n)),时间复杂度一共是O(n2√n),对100%数据卡死了。
100%的数据只需要从70%的数据优化一下,加入筛表求质数,可以完全把质因数分解‘辞退’,因为可以在筛表中加入分解质数的数组来代替,然后将答案数组用这个数组反赋值就可以了。
具体操作:
var
n,m,i,j,primenum,num,maxn:longint;
a,prime,f,p:array[0..1000009] of longint;
isprime:array[1..1000009] of boolean;
pri:array[1..1000000,0..9] of longint;//一共0..9份够了
function max(a,b:longint):longint;
begin
if a>b then
exit(a);
exit(b);
end;
begin
for i:=2 to 1000000 do
begin
if isprime[i] then
continue;
inc(pri[i,0]);//初始化,把当前也分解别忘
pri[i,pri[i,0]]:=i;
inc(primenum);
prime[primenum]:=i;
for j:=2 to 1000000 div i do
begin
isprime[i*j]:=true;
inc(pri[i*j,0]);
pri[i*j,pri[i*j,0]]:=i;//往下分解(分解质因数)
end;
end;
readln(n);
for i:=1 to n do
read(a[i]);
for i:=1 to n do
begin
for j:=1 to pri[a[i],0] do//到分解表初始值
f[i]:=max(f[i],p[pri[a[i],j]]+1);//找序列
for j:=1 to pri[a[i],0] do
p[pri[a[i],j]]:=f[i];//反赋值
end;
for i:=1 to n do
if f[i]>maxn then//找最合适的
maxn:=f[i];
writeln(maxn);
end.
//结束了,没了,真的,就这么气质。