http://codeforces.com/problemset/problem/1025/D
题目大意:给出n个数字,问能不能使用这些数字构成binary search tree,相邻节点gcd>1;
思路:这道题要用到区间dp知识的知识
博客:
https://blog.csdn.net/my_sunshine26/article/details/77141398
区间dp中,把断点k当做树的根节点,若以第 k 个结点为根节点
用 l[i][k] 表示是否能够向左延伸到 i 点
r[k][j] 表示是否能够向右延伸到 j 点。
k 作为[l, r]的根,就可以判断gcd能否用L[l][r] 和 R[l][r] 更新 R[l-1][r] 和 L[l][r+1]。
因为这里l-1或者r-1会是这段区间的父亲,对于每个区间[L,R][L,R]枚举其根节点k,于是这个k把这个区间分成了2个子区间[L,i−1]和[i+1,R]即分别为ii的左儿子和右儿子。当父亲在左边,表示父亲可右扩展到j,左边同理,
can[i][j]表示这个区间可以作为BST ,如果能的话 can[1][n]=1
#include<bits/stdc++.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define tim printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
using namespace std;
typedef long long ll;
typedef long long LL;
typedef pair<int, int> P;
typedef pair<P, ll> LP;
const ll inf = 1e18;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
const int base = 131;
const double pi = acos ( -1 );
const double eps = 1e-8;
inline ll ksm(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
#define a(i,j) a[(i-1)*m+(j)]
#define b(i,j) b[(i-1)*m+(j)]
ll vis[N],num[N];
ll n, m, k, x, y, z;
ll a[N], b[N],c[N];
ll cx, cy, cnt, ans, sum, flag, t, ff,q;
struct node
{
ll to,k;
};
//vector<int> v[N],res;
unordered_map<int, int> mp;
set<string> st;
ll dep[N];
ll l[705][705],r[705][705],v[705][705],can[705][705];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],l[i][i]=r[i][i]=1;
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
v[i][j]=v[j][i]=(__gcd(a[i],a[j])!=1);
}
}
for(int len=1;len<=n;len++)
for(int i=1;i<=n;i++)
{
int j=i+len-1;
if(j>n) break;
for(int k=i;k<=j;k++)
{
if(l[i][k]&&r[k][j])
{
can[i][j]=1;
if(v[i-1][k]) r[i-1][j]=1;//父节点在左
if(v[k][j+1]) l[i][j+1]=1;//父节点在右
}
}
}
if(can[1][n]) cout<<"Yes";
else cout<<"No";
}