版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/81902706
朴素的DP想FA是,确定一段区间l到r,根节点为u,能否构成一棵子树,但这样区间有n^3个状态,然后由于要枚举根节点,导致不必要的浪费,趋近n^4的枚举,而且这个700^3 1s时限,必超时,然后我们枚举区间的根节点的时候,是要判断枚举左边区间的根节点和右边区间的根节点链接当前区间枚举出的根节点,其实没必要枚举这么多,直接每一段l,r区间能否以l-1或r+1为根节点的父节点,其实和原本的DP也是等价的,不过是减少了状态记录量,却优化掉了DP数组的一维,复杂度也减到n^3,注意因为1-n的区间是无所谓的,一定要把每个点都跟0号和n+1号点gcd标记为大于1,那么只要f[1][n][0]或f[1][n][1]能够为true就星
#include<cstdio>
#include<cstring>
#define maxl 710
int n;
bool flag;
int a[maxl];
bool f[maxl][maxl][2],to[maxl][maxl];
inline int gcd(int a,int b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(gcd(a[i],a[j])>1)
to[i][j]=true,to[j][i]=true;
for(int i=1;i<=n;i++)
{
to[0][i]=true;to[i][0]=true;
to[i][n+1]=true;to[n+1][i]=true;
if(to[i][i-1])
f[i][i][0]=true;
if(to[i][i+1])
f[i][i][1]=true;
}
int j;
for(int len=1;len<n;len++)
for(int i=1;i+len<=n;i++)
{
j=i+len;
for(int k=i;k<=j;k++)
if((i==k || f[i][k-1][1]) && (j==k || f[k+1][j][0]))
{
if(to[i-1][k])
f[i][j][0]=true;
if(to[j+1][k])
f[i][j][1]=true;
}
}
if(f[1][n][0] || f[1][n][1])
printf("Yes");
else
printf("No");
return 0;
}