题意:
长度为的严格递增序列,第个数是。
用这些数构造一个二叉搜索树。
每个数必须用一次,不多不少,除此之外再无限制。
问你是否可以构造出二叉搜索树。
题解:
区间 。
表示 这个区间不可以作为 的左子树。
表示 这个区间可以作为 的左子树。
表示 这个区间可以作为 的右子树。
表示 这个区间可以作为 的右子树。
枚举区间结合点 ,去结合 和 。
感受:
这四个小时我被这道题虐的很舒服。
这道题是通过标签math的2000分题搜索出来的,仅仅用到了__gcd函数,真是无语。
这道题不给2200分吗,好吧只能证明我真的不会区间dp。。。。。。
我曾以为我会区间dp,现在看来就是笑话。。。。。。
代码:
#include<bits/stdc++.h>
using namespace std ;
const int maxn = 705 ;
int n ;
int a[maxn] ;
bool g[maxn][maxn] ;
bool dp[maxn][maxn][2] ;
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 ; j <= n ; j ++)
g[i][j] = g[j][i] = __gcd(a[i] , a[j]) > 1 ;
for(int i = 1 ; i <= n - 1 ; i ++)
dp[i][i][0] = __gcd(a[i] , a[i + 1]) > 1 ;
for(int i = 2 ; i <= n ; i ++)
dp[i][i][1] = __gcd(a[i - 1] , a[i]) > 1 ;
for(int len = 1 ; len <= n - 1 ; len ++)
{
for(int i = 1 ; i + len <= n ; i ++)
{
int j = i + len ;
for(int k = i ; k <= j ; k ++)
{
if(!(k - 1 < i || dp[i][k - 1][0])) continue ;
if(!(k + 1 > j || dp[k + 1][j][1])) continue ;
if(g[k][j + 1]) dp[i][j][0] = 1 ;
if(g[k][i - 1]) dp[i][j][1] = 1 ;
}
}
}
bool flag = 0 ;
for(int k = 1 ; k <= n ; k ++)
{
if(!(k - 1 < 1 || dp[1][k - 1][0])) continue ;
if(!(k + 1 > n || dp[k + 1][n][1])) continue ;
flag = 1 ;
}
if(flag) printf("Yes\n") ;
else printf("No\n") ;
return 0 ;
}