洛谷题面传送门 & Atcoder 题面传送门

12 天以前做的题了,到现在才补/yun

做了一晚上+一早上终于 AC 了,写篇题解纪念一下

首先考虑如果全是 \(-1\)​ 怎么处理。由于我们不关心每个 pair 中的 max 是多少,并且显然每个 pair 的最小值都是两两不同的,因此我们可以考虑有多少个最小值组成的集合,然后答案乘上 \(n!\) 即可。而显然如果我们将“作为某个 pair 的最小值”的位置放上一个左括号,“不作为某个 pair 的最小值”的位置放上一个右括号,那么一个集合符合条件当且仅当这个集合对应的括号序列是一个合法括号序列,卡特兰数算算即可。

接下来思考存在某些数固定下来的情况怎么处理,显然我们可以将所有 pair 分为三类:\((-1,-1),(-1,x),(x,y)\),第三类的最小值显然是固定的,我们可以将这样的 \((x,y)\) 中的 \(x,y\) 设为访问过,然后只考虑那些没有访问过的元素。显然带上“某些值固定”这个限制条件后就无法直接套用组合数了,并且显然这个数据范围也不是让你纯组合数学就过的,因此考虑一个 DP。受到上面括号序列这个思想的启发,我们考虑这样一个过程:

  1. 我们考虑有一个长度为 \(m\) 的括号序列,你要在里面填上 \(m/2\) 个左括号和 \(m/2\)​ 个右括号,其中 \(m=2n-2\times\text{两个位置都已经确定了的 pair 的对数}\)
  2. 括号有方括号和圆括号之分,给定 \(k\)​ 个位置,填上的括号必须为方括号,另外 \(m-k\) 个位置填上的括号必须为圆括号。
  3. 填好左右括号之后,你要对于所有右方括号,在前面找一个左圆括号匹配,并且满足去掉这些已经匹配过的括号之后,剩下的括号在不分方括号和圆括号的情况下仍能组成一个合法括号序列

两个方案不同当且仅当括号序列不同或者存在某个右方括号,满足与其匹配的左圆括号位置不同。

够清晰的了吧

我们考虑 DP,事实证明正着 DP 是不好处理左圆括号与右方括号匹配这件事情的,因此考虑倒着 DP,\(dp_{i,j,k}\) 表示钦定了第 \(i\) 个位置到第 \(m\) 个位置上填括号的方案,还剩 \(j\) 个 ‘)’ 和 \(k\) 个 ‘]’ 没有匹配的方案数。那么考虑第 \(i-1\) 个位置:

  • 如果它只能填方括号:

    • 如果填左括号,那么它只能与圆括号匹配,\(dp_{i,j,k}\to dp_{i-1,j-1,k}\)
    • 如果填右括号,那么未匹配的 ‘)’ 个数加一,\(dp_{i,j,k}\to dp_{i-1,j+1,k}\)
  • 如果它只能填圆括号:
    • 如果填左括号,那么有两种可能,与圆括号匹配,由于这种情况是不在乎它与哪个圆括号匹配的,因此贡献只有 \(1\),即 \(dp_{i,j,k}\to dp_{i-1,j-1,k}\),或者它也可以与方括号匹配,显然每个左圆括号与哪个右方括号匹配都是不同的,因此有 \(k\) 种可能,\(dp_{i,j,k}·k\to dp_{i-1,j,k-1}\)
    • 如果填右括号,那么未匹配的 ‘)’ 个数加一,\(dp_{i,j,k}\to dp_{i-1,j,k+1}\)

随便推推即可,最终答案记得乘个 \(((n-m)/2)!\)。时空复杂度均 \(\mathcal O(n^3)\)​

const int MAXN=600;
const int MOD=1e9+7;
int n,a[MAXN+5],vis[MAXN+5],id[MAXN+5],m=0,is[MAXN+5];
int dp[MAXN+5][MAXN+5][MAXN+5];
void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int main(){
scanf("%d",&n);
for(int i=1;i<=n<<1;i++) scanf("%d",&a[i]);
for(int i=1;i<=n<<1;i+=2) if(~a[i]&&~a[i+1]) vis[a[i]]=vis[a[i+1]]=1;
for(int i=1;i<=n<<1;i++) if(!vis[i]) id[i]=++m;
for(int i=1;i<=n<<1;i+=2){
if(~a[i]&&!~a[i+1]) is[id[a[i]]]=1;
if(!~a[i]&&~a[i+1]) is[id[a[i+1]]]=1;
} dp[m+1][0][0]=1;
// for(int i=1;i<=m;i++) printf("%d\n",is[i]);
for(int i=m;i;i--) for(int j=0;j<=m-i;j++) for(int k=0;k+j<=m-i;k++){
if(is[i]){
add(dp[i][j][k+1],dp[i+1][j][k]);
if(j) add(dp[i][j-1][k],dp[i+1][j][k]);
} else {
add(dp[i][j+1][k],dp[i+1][j][k]);
if(k) add(dp[i][j][k-1],1ll*dp[i+1][j][k]*k%MOD);
if(j) add(dp[i][j-1][k],dp[i+1][j][k]);
} //printf("%d %d %d %d\n",i,j,k,dp[i][j][k]);
} int res=dp[1][0][0];
int cc=0;for(int i=1;i<=(n<<1);i+=2) cc+=((!~a[i])&&(!~a[i+1]));
for(int i=1;i<=cc;i++) res=1ll*res*i%MOD;
printf("%d\n",res);
return 0;
}
/*
6
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
*/

评测记录

Atcoder Grand Contest 030 F - Permutation and Minimum(DP)的更多相关文章

  1. Atcoder Grand Contest 034 F - RNG and XOR(FWT)

    Atcoder 题面传送门 & 洛谷题面传送门 tsc 考试前 A 的题了,结果到现在才写这篇题解--为了 2mol 我已经一周没碰键盘了,现在 2mol 结束算是可以短暂的春天 短暂地卷一会 ...

  2. Atcoder Grand Contest 024 E - Sequence Growing Hard(dp+思维)

    题目传送门 典型的 Atcoder 风格的计数 dp. 题目可以转化为每次在序列中插入一个 \([1,k]\) 的数,共操作 \(n\) 次,满足后一个序列的字典序严格大于前一个序列,问有多少种操作序 ...

  3. Atcoder Grand Contest 003 F - Fraction of Fractal(矩阵乘法)

    Atcoder 题面传送门 & 洛谷题面传送门 Yet another AGC F,然鹅这次就没能自己想出来了-- 首先需注意到题目中有一个条件叫做"黑格子组成的连通块是四联通的&q ...

  4. JZOJ5405 & AtCoder Grand Contest 001 F. Permutation

    题目大意 给出一个长度为\(n\)的排列\(P\)与一个正整数\(k\). 你需要进行如下操作任意次, 使得排列\(P\)的字典序尽量小. 对于两个满足\(|i-j|>=k\) 且\(|P_i- ...

  5. Atcoder Grand Contest 016 F - Games on DAG(状压 dp)

    洛谷题面传送门 & Atcoder 题面传送门 如何看待 tzc 补他一个月前做的题目的题解 首先根据 SG 定理先手必输当且仅当 \(\text{SG}(1)=\text{SG}(2)\). ...

  6. Atcoder Grand Contest 010 C - Cleaning 树贪心(伪)

    C - Cleaning 题目连接: http://agc010.contest.atcoder.jp/tasks/agc010_c Description There is a tree with ...

  7. Atcoder Grand Contest 001 D - Arrays and Palindrome(构造)

    Atcoder 题面传送门 洛谷题面传送门 又是道思维题,又是道把我搞自闭的题. 首先考虑对于固定的 \(a_1,a_2,\dots,a_n;b_1,b_2,\dots,b_m\) 怎样判定是否合法, ...

  8. AtCoder Beginner Contest 122 D - We Like AGC (DP)

    D - We Like AGC Time Limit: 2 sec / Memory Limit: 1024 MB Score : 400400 points Problem Statement Yo ...

  9. 【AGC030F】Permutation and Minimum(DP)

    题目链接 题解 首先可以想到分组后,去掉两边都填了数的组. 然后就会剩下\((-1,-1)\)和\((-1,x)\)或\((x,-1)\)这两种情况 因为是最小值序列的情况数,我们可以考虑从大到小填数 ...

随机推荐

  1. 初次认识指针:C语言*p、p以及&p的区别,*p和**p的区别?

    https://blog.csdn.net/weixin_43115440/article/details/93475460 先要理解地址和数据,你可以想象有很多盒子,每个盒子有对应的号码,那个号码叫 ...

  2. Java---String和StringBuffer类

    Java---String和StringBuffer类 Java String 类 字符串在Java中属于对象,Java提供String类来创建和操作字符串. 创建字符串 创建字符串常用的方法如下: ...

  3. JavaScript之原型与原型链

    前言 ❝ JavaScript常被描述为一种「基于原型的语言」--每个对象都拥有一个「原型对象」,对象以其原型为模板.从原型继承属性和放法.原型对象也可能拥有原型,并从中继承属性和方法,一层一层以此类 ...

  4. Coursera Deep Learning笔记 序列模型(一)循环序列模型[RNN GRU LSTM]

    参考1 参考2 参考3 1. 为什么选择序列模型 序列模型能够应用在许多领域,例如: 语音识别 音乐发生器 情感分类 DNA序列分析 机器翻译 视频动作识别 命名实体识别 这些序列模型都可以称作使用标 ...

  5. UltraSoft - Alpha - Postmortem 事后分析

    Alpha阶段 Postmortem会议 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 主要是解决DDL提醒功能的问题,定义的比较清楚,对典型用户和典 ...

  6. echart3 力引导布局实现节点的提示和折叠

    最近在项目中需要开发一个图表来显示人员的各种属性,类似于一种树形的结构进行显示数据.如果多个人员有同一个属性,那么需要将相同的属性进行连线,即关联起来.即形成一个关系图,由于我自身对echarts稍微 ...

  7. 查找最小生成树:普里姆算法算法(Prim)算法

    一.算法介绍 普里姆算法(Prim's algorithm),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之 ...

  8. 手写vue-router & 什么是Vue插件

    博文分享 这篇文章你可以学习到: 实现一个自己的vue-router 了解什么是Vue的插件 学习b站大佬后做的笔记整理和源码实现 1.1.3一步一步带你弄懂vue-router核心原理及实现哔哩哔哩 ...

  9. 从零开始 DIY 智能家居 - 智能开窗器

    前言 做完智慧浇水器之后对这种可以节省时间和精力的场景总有一种谜之向往(懒鬼是这样的),这次我准备做一个可以自动开窗的装置,结合之前的甲醛检测传感器就可以实现甲醛含量过高自动开窗通风,之后还可以把燃气 ...

  10. PCIE基本知识

    转载:https://zhuanlan.zhihu.com/p/139656925 前言 之前主要都在做FPGA算法层面的东西,最近觉得对于接口方面的知识比较欠缺,打算以PCI-E为例来系统的学习一下 ...