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

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

题意:

有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的数大。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#define MP make_pair
using namespace std; typedef long long LL; const int maxn = ; int n, k; vector<int> G[maxn], req[maxn]; LL d[maxn][maxn]; bool check(int L, int R, int l, int r)
{
for(int i = ; i < G[l].size(); i++)
{
int v = G[l][i], t = req[l][i];
if(t == -)
{
if(v < L || v > R || v == r) return false;
}
else if(t == -)
{
if(v < L || v > R) return false;
}
else if(!t)
{
if(v != r) return false;
}
else if(t == )
{
if(v >= L && v <= R && v != r) return false;
}
else
{
if(v >= L && v <= R) return false;
}
} for(int i = ; i < G[r].size(); i++)
{
int v = G[r][i], t = req[r][i];
if(t == -)
{
if(v < L || v > R || v == l) return false;
}
else if(t == -)
{
if(v < L || v > R) return false;
}
else if(!t)
{
if(v != l) return false;
}
else if(t == )
{
if(v >= L && v <= R && v != l) return false;
}
else
{
if(v >= L && v <= R) return false;
}
} return true;
} LL dp(int L, int R)
{
LL& ans = d[L][R];
if(ans >= ) return d[L][R];
if(L + == R)
{
if(check(L, R, L, R)) return 1LL;
return ;
} ans = ; if(check(L, R, L, L + ))
ans += dp(L + , R);
if(check(L, R, L, R))
ans += dp(L + , R - );
if(check(L, R, R - , R))
ans += dp(L, R - ); return ans;
} int main()
{
scanf("%d%d", &n, &k);
char eq[];
while(k--)
{
int u, v;
scanf("%d", &u);
scanf("%s", eq);
scanf("%d", &v); int t;
if(strcmp(eq, "<") == ) t = -;
else if(strcmp(eq, "<=") == ) t = -;
else if(strcmp(eq, "=") == ) t = ;
else if(strcmp(eq, ">=") == ) t = ;
else if(strcmp(eq, ">") == ) t = ;
else exit(); if(u == v)
{
if(abs(t) <= ) continue;
else { puts(""); exit(); }
} req[u].push_back(t); req[v].push_back(-t);
G[u].push_back(v); G[v].push_back(u);
} memset(d, -, sizeof(d)); printf("%I64d\n", dp(, n * )); return ;
}

代码君

CodeForces 567F DP Mausoleum的更多相关文章

  1. 【CodeForces 567F】Mausoleum

    寒假最后一题补完啦 ^∀^ 题意 1到n每个数字有两个,排成先不降后不升的序列,比如112332,并且满足k个形如 3 <= 6 代表第三个数字要≤第六个数字这样的约束要求,求有多少种排法. 分 ...

  2. Two Melodies CodeForces - 813D (DP,技巧)

    https://codeforces.com/problemset/problem/813/D dp[i][j] = 一条链以i结尾, 另一条链以j结尾的最大值 关键要保证转移时两条链不能相交 #in ...

  3. Consecutive Subsequence CodeForces - 977F(dp)

    Consecutive Subsequence CodeForces - 977F 题目大意:输出一序列中的最大的连续数列的长度和与其对应的下标(连续是指 7 8 9这样的数列) 解题思路: 状态:把 ...

  4. codeforces的dp专题

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

  5. Codeforces 721C [dp][拓扑排序]

    /* 题意:给你一个有向无环图.给一个限定t. 问从1点到n点,在不超过t的情况下,最多可以拜访几个点. 保证至少有一条路时限不超过t. 思路: 1.由无后向性我们可以知道(取决于该图是一个DAG), ...

  6. CodeForces 607C (DP) Hard problem

    题目:这里 题意:给定n个字符串,每个字符串可以进行一项操作,就是将这个字符串交换,就是该字符串的第一个和最后一个交换,第二个和倒数第二个交换,以此类推,当然可以选择对于 该字符串进行或不进行这项操作 ...

  7. Codeforces 611d [DP][字符串]

    /* 题意:给一个长度不超过5000的字符串,每个字符都是0到9的数字. 要求将整个字符串划分成严格递增的几个数字,并且不允许前导零. 思路: 1.很开心得发现,当我在前i个区间以后再加一个区间的时候 ...

  8. Codeforces 404D [DP]

    /* 我是一个习惯后悔,但是没办法忍受内疚感的二货== 这题是个无脑dp,但是比赛大概20min没出...其实最后5min我好好想想简单化边界条件,可以出的. 题意: 给你一个长度为1e6的由?*01 ...

  9. Codeforces 119C DP

    题意: 有n天,m门课和常数k; 每天上一门课,每门课程有两个属性,最少作业量a,最多作业量b,和难度c. 1<=a<=b<=1e16 c<=100 1<=n<=m ...

随机推荐

  1. JAVA的API部分介绍

    个人理解: Object作为最大的父类,里面存在不少方法,可以在API中具体的查找.比如可以帮助查看是否相同的equals方法,不过要想看具体属性是否相同需要得重写,打印.调用对象相当于调用其tost ...

  2. NIO学习之Channel

    一.Channel基础 通道是一个对象,通过它可以读取和写入数据,Channel就是通向什么的道路,为数据的流向提供渠道: 在传统IO中,我们要读取一个文件中的内容使用Inputstream,该str ...

  3. 【转】说说Runnable与Callable

    说说Runnable与Callable   Callable接口:   Runnable接口: 相同点: 两者都是接口:(废话) 两者都可用来编写多线程程序: 两者都需要调用Thread.start( ...

  4. Web前端体系的脉络结构

    Web前端技术由 html.css 和 javascript 三大部分构成,是一个庞大而复杂的技术体系,其复杂程度不低于任何一门后端语言.而我们在学习它的时候往往是先从某一个点切入,然后不断地接触和学 ...

  5. C# List的使用

    1.所需引入的命名空间: using System.Collections.Generic; 2.初始化 [1]空: List<int> list = new List<int> ...

  6. CentOS 7安装Docker服务详细过程

    ---恢复内容开始--- Docker 简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟 ...

  7. Azure 镜像市场支持一键部署到云

    本视频教程介绍了Azure 镜像市场和一键部署到云. Azure 镜像市场(AMP)由世纪互联运营,是一个联机应用程序和服务市场,它通过独立软件服务商(ISV)能够成为 Azure 客户(Custom ...

  8. svn与git区别简介,git分支操作在mac客户端soureTree和使用命令行如何实现

    svn与git区别简介: 性能方面(经过实践的) svn:下载速度慢,因为它其中的源文件太多,并且在show log日志的时候每次都需要去服务器拉取,速度很慢 git:下载速度快,并且git clon ...

  9. python基础教程总结3—字典

    1.字典 1.1 字典类型与序列类型的区别: 存取和访问数据的方式不同. 序列类型只用数字类型的键(从序列的开始按数值顺序索引): 映射类型可以用其他对象类型作键(如:数字.字符串.元祖,一般用字符串 ...

  10. 【UML】类图Class diagram(转)

    http://blog.csdn.net/sds15732622190/article/details/48860711 前言 说到UML,相信大家就能立刻反应出其中的类图,为什么这么说呢,类图和用例 ...