csp-M4-C-宇宙狗的危机

题意描述

在瑞神大战宇宙射线中我们了解到了宇宙狗的厉害之处,虽然宇宙狗凶神恶煞,但是宇宙狗有一个很可爱的女朋友。

最近,他的女朋友得到了一些数,同时,她还很喜欢树,所以她打算把得到的数拼成一颗树。

这一天,她快拼完了,同时她和好友相约假期出去玩。贪吃的宇宙狗不小心把树的树枝都吃掉了。所以恐惧包围了宇宙狗,他现在要恢复整棵树,但是它只知道这棵树是一颗二叉搜索树,同时任意树边相连的两个节点的gcd(greatest common divisor)都超过1。

但是宇宙狗只会发射宇宙射线,他来请求你的帮助,问你能否帮他解决这个问题。

补充知识:

GCD:最大公约数,两个或多个整数共有约数中最大的一个 ,例如8和6的最大公约数是2。

一个简短的用辗转相除法求gcd的例子:

int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}

输入
输入第一行一个t,表示数据组数。

对于每组数据,第一行输入一个n,表示数的个数

接下来一行有n个数​,输入保证是升序的。

输出
每组数据输出一行,如果能够造出来满足题目描述的树,输出Yes,否则输出No。
无行末空格。

输入样例 1

1
6
3 6 9 18 36 108
1
2
3
输出样例 1

Yes
1
输入样例 2

2
2
7 17
9
4 8 10 12 15 18 33 44 81
1
2
3
4
5
输出样例2

No
Yes

思路:

dp构建可行二叉搜索树!

所有的数据都是有序的,可以考虑区间dp。to_l[i][j]代表[i,j-1]是否可作为j的左子树。to_r[i][j]表示[i+1,j]是否可以作为i的右子树。

转移条件为:if (GCD[l-1][root]>1)R[l-1][r]=1; if (GCD[r+1][root]>1)L[l][r+1]=1;

当[l,r]为[1,n]时说明可以构建符合题意的树,如果枚举结束都到不了[1,n]说明不可以构建符合题意的树。GCD数组记录两点gcd.

初始化时注意将 to_l[i][i]和to_r[i][i]都赋值为1,因为当点i的左子树或者右子树为空时一定是符合题意的

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 const int maxn=770;
 5 int n,t;
 6 int a[maxn],GCD[maxn][maxn] ;
 7 bool to_l[maxn][maxn],to_r[maxn][maxn];
 8 
 9 int gcd(int a,int b){ 
10     return b == 0 ? a : gcd(b,a%b);
11 }
12 bool solve()
13 {
14     for(int len=1;len<=n;len++)
15         {
16             for(int l=1;l<=n-len+1;l++)
17             {
18                 int r=l+len-1;
19                 for(int k=l;k<=r;k++)
20                 {
21                     if(to_l[k][l] && to_r[k][r])
22                     {
23                         if(len==n)
24                         {
25                             return true; 
26                         }
27                         if(GCD[l-1][k] > 1) 
28                             to_r[l-1][r]=1;
29                         if(GCD[k][r+1] > 1) 
30                             to_l[r+1][l]=1; 
31                     }
32                 }
33             }
34         }
35         return false;
36 }
37 void init(){
38     memset(to_l,0,sizeof(to_l));
39     memset(to_r,0,sizeof(to_r));    
40     for(int i=1;i<=n;i++)
41         {
42             for(int j=i;j<=n;j++)
43             {
44                 
45                 GCD[j][i]=gcd(a[i],a[j]);
46                 GCD[i][j]=GCD[j][i];
47             }
48             to_l[i][i]=1;
49             to_r[i][i]=1;            
50         }                
51 }
52 int main()
53 {
54     cin>>t;
55     while(t--)
56     {
57         //input 
58         cin>>n;
59         for(int i=1;i<=n;i++)
60             cin>>a[i];            
61         //initialize  
62         init();
63         //solve
64         bool flag = solve();
65         if(flag){
66             cout<<"Yes"<<endl;
67         }
68         else cout<<"No"<<endl;
69     }
70     return 0;
71 }

 

posted @ 2020-06-05 12:38  流转~星云  阅读(314)  评论(0编辑  收藏  举报