\(\mathcal{Description}\)

  现 \(2^n\) 个人进行淘汰赛,他们的战力为 \(1\sim 2^n\),战力强者能战胜战力弱者,但是战力在集合 \(\{a_m\}\) 里的人可以放水输给战力为 \(1\) 的人。求让 \(1\) 获胜的初始安排,并要求 \(1\) 依次战胜的人的战力序列的 LIS 长度不小于 \(l\)。

  \(m\le16\),\(l\le n\le9\)。

\(\mathcal{Solution}\)

  出题人你为什么不把题意写在题面里啊?

  第一种方法:枚举 \(1\) 战胜的 \(n\) 个人的战力大小关系 DP,非常轻松,这里不提。

  第二种方法需要灵活地联系 LIS 的各种求法。结合方法一的一些实现细节,可以发现这样维护 LIS 非常合理:按值从小到大将数加入序列,维护每个长度的 LIS 的最前结尾位置。首先将 \(\{a_m\}\) 升序排列,定义状态 \(f(i,S,T)\) 表示考虑了 \(\{a_m\}\) 中前 \(i\) 个数;\(1\) 的战胜序列中集合 \(S\) 内的位置已经使用;其中集合 \(T\subseteq S\) 内的位置是最优 LIS 的结尾。组合数计算在竞标赛树里加一棵子树的方案即可转移。相当于一个 DP 套 DP。复杂度 \(\mathcal O(mn3^n)\)。


  所以写这篇题解的目的是总结一下求 LIS 的方法:

  • \(f(i)\) 表示以 \(i\) 结尾的最长 LIS。优点:好想好写。
  • \(f(i)\) 表示(考虑了前缀位置后)LIS 长度为 \(i\) 的最小结尾数。优点:可将值记入状态
  • \(f(i)\) 表示(考虑了前若干小的值后)LIS 长度为 \(i\) 的最小结尾位置。优点:可将位置记入状态

\(\mathcal{Code}\)

/*~Rainybunny~*/

#include <bits/stdc++.h>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i ) const int MAXN = 9, MAXM = 16;
int n, m, l, P, a[MAXM + 5], f[2][1 << MAXN][1 << MAXN];
int fac[1 << MAXN | 5], ifac[1 << MAXN | 5]; inline void chkmax( int& u, const int v ) { u < v && ( u = v ); }
inline int mul( const int u, const int v ) { return 1ll * u * v % P; }
inline int add( int u, const int v ) { return ( u += v ) < P ? u : u - P; }
inline void addeq( int& u, const int v ) { ( u += v ) >= P && ( u -= P ); }
inline int mpow( int u, int v ) {
int ret = 1;
for ( ; v; u = mul( u, u ), v >>= 1 ) ret = mul( ret, v & 1 ? u : 1 );
return ret;
} inline void init() {
fac[0] = 1;
rep ( i, 1, 1 << n ) fac[i] = mul( i, fac[i - 1] );
ifac[1 << n] = mpow( fac[1 << n], P - 2 );
per ( i, ( 1 << n ) - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );
} inline int bino( const int u, const int v ) {
return v < 0 || u < v ? 0 : mul( fac[u], mul( ifac[v], ifac[u - v] ) );
} int main() {
freopen( "punch.in", "r", stdin );
freopen( "punch.out", "w", stdout ); scanf( "%d %d %d %d", &n, &m, &l, &P ), init();
rep ( i, 1, m ) scanf( "%d", &a[i] );
std::sort( a + 1, a + m + 1 ); f[0][0][0] = 1;
rep ( i, 1, m ) {
int sta = ~i & 1;
rep ( S, 0, ( 1 << n ) - 1 ) for ( int T = S; ; T = ( T - 1 ) & S ) {
int& cur = f[sta][S][T];
if ( !cur && !T ) break;
if ( !cur ) continue; addeq( f[!sta][S][T], cur );
rep ( j, 0, n - 1 ) if ( ~S >> j & 1 ) {
int c = mul( fac[1 << j],
bino( a[i] - 2 - S, ( 1 << j ) - 1 ) );
if ( !c ) continue; addeq( f[!sta][S | 1 << j][( T >> j ?
( T >> j & ( T >> j ) - 1 ) << j |
T & ( 1 << j ) - 1 : T ) | 1 << j], mul( cur, c ) );
} cur = 0;
if ( !T ) break;
}
} int ans = 0;
rep ( T, 0, ( 1 << n ) - 1 ) if ( __builtin_popcount( T ) >= l ) {
addeq( ans, f[m & 1][( 1 << n ) - 1][T] );
}
printf( "%d\n", mul( ans, 1 << n ) );
return 0;
}

Solution -「牛客 NOIP 模拟赛」打拳的更多相关文章

  1. 「NOIP模拟赛」数位和乘积(dp,高精)

    统计方案数,要么组合数,要么递推(dp)了. 这是有模拟赛历史以来爆炸最狠的一次 T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0 T3看错题本来简单模拟又 ...

  2. 「NOIP模拟赛」Round 3

    Tag 计数+LIS, 二分+ST表, 计数+记搜 A. 改造二叉树 Description 题面 Solution 如果目标序列非严格递增,或者说目标序列是不下降的,那么答案就是 \(n\) 减去最 ...

  3. 「NOIP模拟赛」Round 2

    Tag 递推,状压DP,最短路 A. 篮球比赛1 题面 \(Milky\ Way\)的代码 #include <cstdio> const int N = 2000, xzy = 1e9 ...

  4. 计蒜客NOIP模拟赛6 D1T1Diamond-square

    Diamond-square 算法是一种能够用于生成噪声的算法,现在我们考虑这个算法的一个变种. 你有一个 2^n\times 2^n2​n​​×2​n​​ 的网格,一共有 (2^n+1)^2(2​n ...

  5. 计蒜客NOIP模拟赛4 D2T1 鬼脚图

    鬼脚图,又称画鬼脚,在日本称作阿弥陀签,是一种经典游戏,也是一种简易的决策方法,常常用来抽签或决定分配组合. 下图就是一张鬼脚图,其包含若干条竖线和若干条横线.请注意,横线只能水平连接相邻的两条竖线, ...

  6. 计蒜客NOIP模拟赛4 D1T2小X的密室

    小 X 正困在一个密室里,他希望尽快逃出密室. 密室中有 N 个房间,初始时,小 X 在 1 号房间,而出口在 N 号房间. 密室的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条 ...

  7. 计蒜客 NOIP模拟赛(3) D1T1火山喷发

    火山喷发对所有附近的生物具有毁灭性的影响.在本题中,我们希望用数值来模拟这一过程. 在环境里有 nnn 个生物分别具有 A1,A2,⋯,An​​点生命值,一次火山喷发总计 M轮,每轮造成 1点伤害,等 ...

  8. 计蒜客NOIP模拟赛(2) D2T3 银河战舰

    [问题描述]    瑞奥和玛德利德是非常好的朋友.瑞奥平时的爱好是吹牛,玛德利德的爱好是戳穿瑞奥吹的牛.    这天瑞奥和玛德利德来到了宇宙空间站,瑞奥向玛德利德炫耀这个空间站里所有的银河战舰都是自己 ...

  9. 计蒜客NOIP模拟赛5 D1T1 机智的 AmyZhi

    那年一个雨季,AmyZhi 在校门外弯身买参考书. 这时 SiriusRen 走过来,一言不合甩给她一道“自认为”很难的题: --------------- 给你一个数字 NN(NN 的范围是 11  ...

随机推荐

  1. CentOS 7 如何清空文件内容

    https://www.cnblogs.com/zqifa/p/linux-vim-4.html 方法1.在非编辑状态下使用快捷键gg跳至首行头部,再使用dG即可清空,或 输入"%d&quo ...

  2. 怎样修改自己的登录shell

    问题 我只是Linux系统的普通用户,没有权限调用chsh命令修改自己的登录shell. bash-4.1$ chsh --help Usage: chsh [ -s shell ] [ --list ...

  3. GoWeb之gin框架

    Gin 是一个 go 写的 web 框架,具有高性能的优点.官方地址:https://github.com/gin-gonic/gin 一.快速上手 安装 go mod init go get -u ...

  4. sqoop的使用之import导入到HDFS

    原文链接: https://www.toutiao.com/i6772128429614563843/ 首先我们已经安装好sqoop了,如果没有安装好参考文档<快速搭建CDH-Hadoop-Hi ...

  5. 51 Nod 1133 不重叠的线段 (贪心算法)

    原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1133 题目分析:感觉这到第不应该被分到二级算法题,比 109 ...

  6. test_5 排序‘+’、‘-’

    题目是:有一组"+"和"-"符号,要求将"+"排到左边,"-"排到右边,写出具体的实现方法. 方法一: l=['-', ...

  7. Go - 如何编写 ProtoBuf 插件 (三) ?

    目录 前言 演示代码 小结 推荐阅读 前言 上篇文章<Go - 如何编写 ProtoBuf 插件 (二) >,分享了基于 自定义选项 定义了 interceptor 插件,然后在 hell ...

  8. 《剑指offer》面试题55 - II. 平衡二叉树

    问题描述 输入一棵二叉树的根节点,判断该树是不是平衡二叉树.如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树. 示例 1: 给定二叉树 [3,9,20,null,null, ...

  9. 为什么JavaWeb要分层

    首先bai让我们坐着时光机回到n年前的web开发.那个时候最早du都是静态的html页面,zhi后来有了数据库,有了所谓dao的动态页面,然后程序猿在编码的时候,会把所有的代码都写在页面上,包括数据库 ...

  10. 【C++】STL算法

    STL算法 标签:c++ 目录 STL算法 一.不变序列算法 1.熟悉的min(), max() 2.找最值还自己动手么?不了不了 3.熟悉的find()和新学会的count() 二.变值算法 1.f ...