樣例輸入1:
1
6
3 6 9 18 36 108
樣例輸出1:
Yes
樣例輸入2:
2
2
7 17
9
4 8 10 12 15 18 33 44 81
樣例輸出2:
No
Yes
模擬課上的時候看到這題就沒什麼頭緒,課下看了別人的代碼才懂的。
區間DP,can_l[i][j]表示[i,j-1]是否可以作爲j的左子樹,can_r[i][j]表示[i+1,j]是否可以作爲i的右子樹,can_l[i][i],can_r[i][i]均爲1,因爲當i的左右子樹爲空時是符合的。
轉移方程:if(g[l-1][k]>1) can_r[l-1][r]=1 if(g[r+1][k]>1) can_l[l][r+1]=1
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int T;
int N;
int a[710];
int g[710][710];
bool can_l[710][710],can_r[710][710];
bool func()
{
for(int len=1;len<=N;len++)
{
for(int l=1;l<=N-len+1;l++)
{
int r=l+len-1;
for(int k=1;k<=r;k++)
{
if(can_l[k][l]&&can_r[k][r])
{
if(len==N)
{
return true;
}
if(g[l-1][k]>1)
can_r[l-1][r]=1;
if(g[k][r+1]>1)
can_l[r+1][l]=1;
}
}
}
}
return false;
}
int main()
{
cin>>T;
while(T--)
{
memset(g,0,sizeof(g));
memset(can_l,0,sizeof(can_l));
memset(can_r,0,sizeof(can_r));
cin>>N;
for(int i=1;i<=N;i++)
{
cin>>a[i];
}
for(int i=1;i<=N;i++)
{
for(int j=i;j<=N;j++)
{
g[i][j]=g[j][i]=gcd(a[i],a[j]);
}
can_l[i][i]=can_r[i][i]=1;
}
bool flag=func();
if(flag)
cout<<"Yes\n";
else
cout<<"No\n";
}
}