题意:类似于就最长字串,可是这里的判定方式没有严格的可以利用的偏序关系,所以要区别对待。
做法:觉得很像图论啊。两个数字如果可以连在一起,那么它们一定有公共的质因子。可以吧1--100000之内的素数看做是点,求以某个素数为结尾的最长边的长度。
首先,先对每个元素进行分解,得出来一个个质因子,然后任取两个,以一个为起点一个为终点,从而形成一条有向边。然后连接以前的记录的每个质因子,修改每个质因子为结尾的边的长度。
#include <iostream>
#include <cstdio>
#include <cstring>
#define LMT 1000005
#define M 100003 // [1..M]
#define clr(x, k) memset((x), (k), sizeof(x))
using namespace std;
int have[LMT],tem[LMT];
int d[M],p;
bool f[M];
void Getprime()
{
int i, j;
p = 0;
clr(f, 0);
for (i=2;i<M;++i)
{
if (!f[i]) d[p++] = i;
for (j=0;(j<p && i*d[j]<M);++j)
{
f[i*d[j]] = 1;
if (i % d[j] == 0) break;
}
}
}
void work(int x)
{
int sz=0,now[25];
for(int i=0;i<p&&x>1;i++)
if(x%d[i]==0)
{
tem[d[i]]=have[d[i]];
now[sz++]=d[i];
while(x%d[i]==0)x/=d[i];
}
for(int i=0;i<sz;i++)
for(int j=0;j<sz;j++)
if(have[now[i]]<tem[now[j]]+1)
have[now[i]]=tem[now[j]]+1;
}
int main()
{
int x,ans=1,n;
Getprime();
scanf("%d",&n);
while(n--)
{
scanf("%d",&x);
work(x);
}
for(int i=0;i<LMT;i++)
if(ans<have[i])ans=have[i];
printf("%d\n",ans);
return 0;
}