51NOD1522&CF567F 上下序列/Mausoleum DP
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51NOD1522&CF567F 上下序列/Mausoleum DP相关的知识,希望对你有一定的参考价值。
大致题意:你有$1$到$N$的所有正整数每个数两个,现在需要你将它排成一个序列,使得序列为单峰序列(存在一个$j in [1,2N]$满足$a_1 leq a_2 leq .. leq a_j geq a_{j+1} ... geq a_{2N}$),并且满足输入中给出的$K$个约束条件。$N leq 35 , K leq 100$
因为序列要满足单峰,所以考虑从小到大在没有加入数字的序列位置的最左和最右加入元素,这样序列将会一直满足单峰性质
考虑状态$f_{p,q}$表示左边已经填了$p$个,右边填了$q$个的方案(其实可以压掉其中一维),考虑第$i$个数字的转移,有$3$种:
$a:$将这两个$i$都放在序列最左边;$b:$将这两个$i$放在序列最右边;$c.$将这两个$i$一个放一边。
对于$K$个约束条件我们可以在加入的时候直接判断:当前加入的两个数相等,没加入的位置的数必定比当前加的数大,而其他已经填好的地方一定比当前的数小。
最后的答案是$frac{sumlimits_{i=0}^{2n}f_{i,2n-i}}{3}$,除3是因为对于最后一次加入,$abc$三种方案都是可行的,但是我们只能算一种。
注意判断约束条件时的细节,约束条件的存储可以使用类似邻接表的方法,在加入约束条件时如加入无向边一样变成两个约束条件,判断起来会方便一些。
1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
4
5 int ans[72][72] , numOp[72];
6
7 vector < int > num[72] , op[72];
8 map < string , int > opToNum;
9
10 bool ifOK(int l , int r , int que1 , int que2){
11 //特别注意判断que1位置与que2位置有联系的情况
12 for(int i = 0 ; i < numOp[que1] ; i++)
13 switch(op[que1][i]){
14 case 1:
15 if(num[que1][i] < r && num[que1][i] > l || num[que1][i] == que2)
16 return 0;
17 break;
18 case 2:
19 if(num[que1][i] < r && num[que1][i] > l && num[que1][i] != que2)
20 return 0;
21 break;
22 case 3:
23 if(!(num[que1][i] == que2))
24 return 0;
25 break;
26 case 4:
27 if(!(num[que1][i] <= r && num[que1][i] >= l || num[que1][i] == que2))
28 return 0;
29 break;
30 case 5:
31 if(!(num[que1][i] < r && num[que1][i] > l) || num[que1][i] == que2)
32 return 0;
33 }
34 for(int i = 0 ; i < numOp[que2] ; i++)
35 switch(op[que2][i]){
36 case 1:
37 if(num[que2][i] < r && num[que2][i] > l || num[que2][i] == que1)
38 return 0;
39 break;
40 case 2:
41 if(num[que2][i] < r && num[que2][i] > l && num[que2][i] != que1)
42 return 0;
43 break;
44 case 3:
45 if(!(num[que2][i] == que1))
46 return 0;
47 break;
48 case 4:
49 if(!(num[que2][i] <= r && num[que2][i] >= l || num[que2][i] == que1))
50 return 0;
51 break;
52 case 5:
53 if(!(num[que2][i] < r && num[que2][i] > l) || num[que2][i] == que1)
54 return 0;
55 }
56 return 1;
57 }
58
59 main(){
60 opToNum.insert(make_pair(">" , 1));
61 opToNum.insert(make_pair(">=" , 2));
62 opToNum.insert(make_pair("=" , 3));
63 opToNum.insert(make_pair("<=" , 4));
64 opToNum.insert(make_pair("<" , 5));
65 int N , K;
66 for(cin >> N >> K ; K ; K--){
67 int a , b , t;
68 string s;
69 cin >> a >> s >> b;
70 t = opToNum.find(s)->second;
71 if(a == b)
72 if(t == 1 || t == 5){
73 cout << 0;
74 return 0;
75 }
76 else
77 continue;
78 num[a].push_back(b);
79 op[a].push_back(t);
80 num[b].push_back(a);
81 op[b].push_back(6 - t);
82 numOp[a]++;
83 numOp[b]++;
84 }
85 ans[0][0] = 1;
86 for(int i = 1 ; i <= N ; i++){
87 //DP
88 for(int j = 2 * i ; j >= 2 ; j--)
89 if(ans[j - 2][2 * i - j] && ifOK(j , 2 * N - 2 * i + j + 1 , j , j - 1))
90 ans[j][2 * i - j] += ans[j - 2][2 * i - j];
91 for(int j = 2 * i ; j >= 2 ; j--)
92 if(ans[2 * i - j][j - 2] && ifOK(2 * i - j , 2 * N - j + 1 , 2 * N - j + 1 , 2 * N - j + 2))
93 ans[2 * i - j][j] += ans[2 * i - j][j - 2];
94 for(int j = 1 ; j < 2 * i ; j++)
95 if(ans[2 * i - j - 1][j - 1] && ifOK(2 * i - j , 2 * N - j + 1 , 2 * i - j , 2 * N - j + 1))
96 ans[2 * i - j][j] += ans[2 * i - j - 1][j - 1];
97 }
98 int all = 0;
99 for(int i = 0 ; i <= 2 * N ; i++)
100 all += ans[i][2 * N - i];
101 cout << all / 3;
102 return 0;
103 }
以上是关于51NOD1522&CF567F 上下序列/Mausoleum DP的主要内容,如果未能解决你的问题,请参考以下文章