本着只贴代码不写分析的题解是在耍流氓的原则,还是决定写点分析。

思路很清晰,参考的官方题解,一下文字仅对题解做一个简要翻译。

题意:

有1~n这n个数,每个数用两次。构成一个长为2n的序列,而且要求序列满足先递增后递减(都是非严格的递增递减)。

再给出k个约束,每个约束形如1 >= 3这种,表示序列的第一个数要不小于第三个数。

问满足约束的合法序列有多少种。

分析:

首先先不考虑这些约束条件,考虑如何构造出这种序列。

考虑两个1放置的位置,因为序列是两边小中间大,所以这两个1要么放在前面两个位置,或者后面两个位置,要么一前一后,而且只有这三种放法。

事实上,不考虑约束条件的话,n个数能得到的合法的序列的个数为3n

因此这些数是1~n从两边往中间放的。

设d(L, R)表示[L, R]这个区间还没放数,满足约束条件的序列个数,则答案为d(1, 2n)

下面考虑如何处理这些不等式:

计算d(L, R)时,比如要放在L和L+1这两个格子,那么就考虑所有和L相关的不等式,以及和L+1相关的不等式。

为了更清楚起见,画一个图看看:

绿色表示已经放好数的区间,黄色表示正要放的两个格子,红色是还未放数的区间。

那么有大小关系:绿色的数 < 黄色的数 < 红色的数,两个黄色格子的数是相等的。

比如有不等式L >= v

如果a[L] == a[v],那么v应该等于L + 1,表示L和v两个位置放同一个数;

如果a[L] > a[v],那么v应该在绿色的区间表示之前已经放过数了,这样放在L的数才能比放在v的数大。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <map>
  7 #define MP make_pair
  8 using namespace std;
  9
 10 typedef long long LL;
 11
 12 const int maxn = 80;
 13
 14 int n, k;
 15
 16 vector<int> G[maxn], req[maxn];
 17
 18 LL d[maxn][maxn];
 19
 20 bool check(int L, int R, int l, int r)
 21 {
 22     for(int i = 0; i < G[l].size(); i++)
 23     {
 24         int v = G[l][i], t = req[l][i];
 25         if(t == -2)
 26         {
 27             if(v < L || v > R || v == r) return false;
 28         }
 29         else if(t == -1)
 30         {
 31             if(v < L || v > R) return false;
 32         }
 33         else if(!t)
 34         {
 35             if(v != r) return false;
 36         }
 37         else if(t == 1)
 38         {
 39             if(v >= L && v <= R && v != r) return false;
 40         }
 41         else
 42         {
 43             if(v >= L && v <= R) return false;
 44         }
 45     }
 46
 47     for(int i = 0; i < G[r].size(); i++)
 48     {
 49         int v = G[r][i], t = req[r][i];
 50         if(t == -2)
 51         {
 52             if(v < L || v > R || v == l) return false;
 53         }
 54         else if(t == -1)
 55         {
 56             if(v < L || v > R) return false;
 57         }
 58         else if(!t)
 59         {
 60             if(v != l) return false;
 61         }
 62         else if(t == 1)
 63         {
 64             if(v >= L && v <= R && v != l) return false;
 65         }
 66         else
 67         {
 68             if(v >= L && v <= R) return false;
 69         }
 70     }
 71
 72     return true;
 73 }
 74
 75 LL dp(int L, int R)
 76 {
 77     LL& ans = d[L][R];
 78     if(ans >= 0) return d[L][R];
 79     if(L + 1 == R)
 80     {
 81         if(check(L, R, L, R)) return 1LL;
 82         return 0;
 83     }
 84
 85     ans = 0;
 86
 87     if(check(L, R, L, L + 1))
 88         ans += dp(L + 2, R);
 89     if(check(L, R, L, R))
 90         ans += dp(L + 1, R - 1);
 91     if(check(L, R, R - 1, R))
 92         ans += dp(L, R - 2);
 93
 94     return ans;
 95 }
 96
 97 int main()
 98 {
 99     scanf("%d%d", &n, &k);
100     char eq[10];
101     while(k--)
102     {
103         int u, v;
104         scanf("%d", &u);
105         scanf("%s", eq);
106         scanf("%d", &v);
107
108         int t;
109         if(strcmp(eq, "<") == 0) t = -2;
110         else if(strcmp(eq, "<=") == 0) t = -1;
111         else if(strcmp(eq, "=") == 0) t = 0;
112         else if(strcmp(eq, ">=") == 0) t = 1;
113         else if(strcmp(eq, ">") == 0) t = 2;
114         else exit(1234);
115
116         if(u == v)
117         {
118             if(abs(t) <= 1) continue;
119             else { puts("0"); exit(0); }
120         }
121
122         req[u].push_back(t); req[v].push_back(-t);
123         G[u].push_back(v); G[v].push_back(u);
124     }
125
126     memset(d, -1, sizeof(d));
127
128     printf("%I64d\n", dp(1, n * 2));
129
130     return 0;
131 }

代码君

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4738710.html

CodeForces 567F DP Mausoleum相关推荐

  1. c语言鸽巢原理,Codeforces 1188C DP 鸽巢原理

    题意:定义一个序列的beauty值为序列中元素之差绝对值的最小值,现在给你一个数组,问所有长度为k的子序列的beauty值的和是多少? 思路:(官方题解)我们先解决这个问题的子问题:我们可以求出bea ...

  2. codeforces的dp专题

    1.(467C)http://codeforces.com/problemset/problem/467/C 题意:有一个长为n的序列,选取k个长度为m的子序列(子序列中不能有位置重复),求所取的k个 ...

  3. G - Hard problem CodeForces - 706C DP

    #include<bits/stdc++.h> using namespace std;typedef long long ll; string a[100000 +10], b[1000 ...

  4. Codeforces 1096F(dp + 树状数组)

    题目链接 题意: 对于长度为$n$的排列,在已知一些位的前提下求逆序对的期望 思路: 将答案分为$3$部分 $1.$$-1$与$-1$之间对答案的贡献.由于逆序对考虑的是数字之间的大小关系,故假设$- ...

  5. Codeforces 1105C (DP)

    题面 传送门 分析 这种计数问题,要不是纯数学推公式,要不就是dp 先处理出[l,r]中除3余0,1,2的数的个数,记为cnt0,cnt1,cnt2 设\(dp[i][j]\)表示前i个数的和除3余j ...

  6. Codeforces 319C DP 斜率优化

    题意:在一颗森林有n颗数,编号从1到n,第i棵树高度是a[i].有一个伐木工想要砍伐这片森林,它的电锯每次可以将树的高度减少1,然后就必须要充电,充电的代价是他已经砍倒的树种编号最大的那颗树的代价(b ...

  7. E. Pencils and Boxes codeforces(思维+dp)

    题目链接:E. Pencils and Boxes 题意: 给出n个数字,分组,每组大小>=k,并且同一组内任意两个数字大小不能超过d 思路: 先从小到大排序.然后dp.起点肯定是第一个数字,然 ...

  8. Dynasty Puzzles CodeForces - 191A+DP二维

    题意:一共给你N个字符串,如果一个字符串的尾部字母和一个字符串的首部字母相同,/那么两个字符串就可以拼接起来,问最长的首尾字母相同的字符串的长度为多少. //思路:DP便利一遍就够了 ,dp[a][b ...

  9. Codeforces 1000D dp

    注意对题意的理解,对于给出的序列,我们需要找出他满足要求的子序列,然后对于每个子序列,再把它分成几个满足要求的子串 . 对于任意一个元素i,我们需要至少往后面走a[i]位,然后从i+a[i]+1开始直 ...

最新文章

  1. java学习之匿名内部类与包装类
  2. 使iPhone手机持续振动
  3. bseg---faglflexta
  4. Java线程之Synchronized用法
  5. AD20学习笔记4---网表导入及模块化布局设计
  6. Jconsole查看Weblogic自定义MBean
  7. HttpClient Get/Post方式调用Http接口
  8. 内部类-----Java
  9. RequestDispatcher对象的应用-请求包含
  10. oracle中的new old 关键字
  11. HTML(超文本语言)
  12. CF125E MST Company
  13. 大厂员工涌入外包:中年失业,外包已是我最好的选择
  14. 2019年python爬虫-我破解了中文裁判网数据挖掘-反爬技术哪些事情
  15. Camera2 YUV_420_888转NV21
  16. 第9章第1节:创建商业计划书封面幻灯片的版式 [PowerPoint精美幻灯片实战教程]
  17. Type-C强光手电快充方案
  18. android广告拦截原理,WebView 广告拦截浅析
  19. JS 日期的获取和计算 ios不兼容问题
  20. Java中double类型保留两位小数

热门文章

  1. 本案例通过ArrayList集合来显示Collection接口中的共性函数
  2. [转]Listview的onItemClickListener无法响应的解决方法
  3. 通过css将多个图标或图片用同一张图片通过定位背景位置调用到页面
  4. 我的奔腾B50 MT豪华版 典雅灰 – 验车篇
  5. C#获取当前路径的方法集合
  6. 子进程 post-installation script 返回了错误号 解决方法
  7. 1109: 胥哥的DOTA-水题(直接做,时间也不超限)
  8. Knative 多容器支持介绍
  9. 你在「动森」里遇到的那些「丑动物」,后来怎么样了?
  10. ASP.NET下载网络图片