cap[i][j]表示点i,j能否连边:
l[i][j]表示以i号点为根节点能否扩展到j,
r[i][j]表示以j号点为根节点能否扩展到i,
然后枚举区间长度与根节点
关键是因为区间左右并没有关联可以分别考虑,就不需要用dp[i][j]来表示ij区间,不用左右对应减少了一个纬度
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int n;
int a[755];
int cap[755][755];
int l[755][755],r[755][755];
int gcd(int x,int y)
{
if(y==0)
return x;
return gcd(y,x%y);
}
int main() {
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(gcd(a[i],a[j])>1)
cap[i][j]=1;
else
cap[i][j]=0;
}
}
memset(l,0,sizeof(l)); memset(r,0,sizeof(r));
for(int i=1;i<=n;i++)
l[i][i]=r[i][i]=1;
for(int k=1;k<=n;k++)
{
for(int i=1;i+k-1<=n;i++)
{
int sta=i,ed=i+k-1;
for(int mid=sta+1;mid<=ed;mid++)
{
int ck1=0,ck2=0;
if(cap[sta][mid]==1)
{
ck1=r[sta+1][mid];
ck2=l[mid][ed];
if(ck1==1 && ck2==1)
l[sta][ed]=1;
}
}
for(int mid=sta;mid<ed;mid++)
{
int ck1=0,ck2=0;
if(cap[mid][ed]==1)
{
ck1=r[sta][mid];
ck2=l[mid][ed-1];
if(ck1==1 && ck2==1)
r[sta][ed]=1;
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(r[1][i]==1 && l[i][n]==1)
ans=1;
}
if(ans==1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}