codeforces1025D 2000分 BST与区间dp的故事

题目传送门

题意:

长度为n的严格递增序列,第i个数是\dpi{150} a_i

用这些数构造一个二叉搜索树。

每个数必须用一次,不多不少,除此之外再无限制。

问你是否可以构造出二叉搜索树。

题解:

区间dp 。

dp[i][j][0] = 0 表示 [i,j] 这个区间不可以作为 j+1 的左子树。

dp[i][j][0] = 1 表示 [i,j] 这个区间可以作为 j+1 的左子树。

dp[i][j][1] = 0 表示 [i,j] 这个区间可以作为 i-1 的右子树。

dp[i][j][1] = 1 表示 [i,j] 这个区间可以作为 i-1 的右子树。

枚举区间结合点 k ,去结合 dp[i][k-1][0] 和 dp[k+1][j][0] 。

感受:

这四个小时我被这道题虐的很舒服。

这道题是通过标签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 ;
}
发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104100606