最长不互质序列————代码与详解

最长不互质序列————代码与详解

【题目】

题目描述

现在有一个长度为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这组数据很好说明(答案是326不互质,63不互质)),这就是这道题的精华之处。对于一下子没有头绪的题目,我们根据数据范围来分析这题的算法,很显然,对于20%的数据根本是水过(暴力也行嘛,虽说我测的时候只有10%【打脸ing】),40%对于纯粹的大暴力肯定过不了(ON4)或更大(一般只能有ON5)的,优化一下ON4))),根据题意,不互质就是两个数有公约数,这里找不等于一的公约数(首选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

23

于是有质因子2的数有:246,共3

      质因子3的数有:36,共两个

其它各有一个。

所以最长序列为:246(完全正确,开心)

再试下之前提到的“上天序列”:263

2

6

3

f[i]2

23

3

 

于是有质因子2的有26,共两个

      质因子3的有63,共两个

不难发现,2663共有一个6(顺序有关系的),合并23单元格,把序列精简为263,共三个。(又对了,啦啦啦)

不过回头再算一下时间复杂度,外层n,内层质因子分解n*√n(注意要两个分解,第一个就是分解,第二个确定答案数组f[]赋值,优化加一个break(几乎是n*√n)),时间复杂度一共是On2√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.

//结束了,没了,真的,就这么气质。

 

 

你可能感兴趣的:(算法,数论,pascal,数论)