题目传送门

https://atcoder.jp/contests/arc093/tasks/arc093_d

题解

由于不论 \(1\) 在哪个位置,一轮轮下来,基本上过程都是相似的,所以不妨假设 \(1\) 在第 \(1\) 个位置。

那么,\(1\) 将以此遇到的对手是 \(p_2, \min\{p_3, p_4\}, \min\{p_5, p_6, p_7, p_8\}, \cdots\)。

令这些数分别为 \(b_0, b_1, \cdots\),其中 \(b_i = \min \limits_{j=2^i + 1}^{2^{j+1}} p_j\),长度为 \(2^i\)。满足题意的 \(b\) 中的任何一个数均没有在 \(a\) 中出现过。

考虑容斥。对于集合 \(S\),需要求出 \(\forall i \in S\),有 \(b_i\) 是 \(a\) 中元素的方案数。

可以使用 dp 来实现。为了方便计数,将 \(a\) 从大到小排序。令 \(dp[i][S]\) 表示集合 \(S\) 中的 \(b\) 值均出现在 \(a\) 中前 \(i\) 个数的方案数。(不考虑没有在 \(a\) 中出现的那些 \(b\) 中的元素)

第一种转移是不选第 \(i\) 个数,转移方法是 \(dp[i][S] \to dp[i+1][S]\);

第二种转移,枚举一个没有在 \(S\) 中出现的位置 \(j\),则可以转移 \(dp[i][S] \cdot \binom{les}{2^j-1} \cdot (2^j)! \to dp[i+1][S \cup \{j\}]\)。

最后,计算集合 \(S\) 的实际方案数的时候,由于之前的 dp 没有考虑那些没有在 \(a\) 中出现的 \(b\),所以还需要乘上 \((2^n - 1 - S)!\)。


下面是代码。状态数一共 \(O(mS)\),转移 \(O(n)\),总时间复杂度 \(O(nmS)\)。

#include<bits/stdc++.h>

#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
} #define lowbit(x) ((x) & -(x)) const int N = 20;
const int M = (1 << 16) + 7;
const int P = 1e9 + 7; int n, m, S;
int a[N], dp[N][M];
int inv[M], fac[M], ifac[M]; inline int smod(int x) { return x >= P ? x - P : x; }
inline void sadd(int &x, int y) { x += y; x >= P ? x -= P : x; }
inline int fpow(int x, int y) {
int ans = 1;
for (; y; y >>= 1, x = (ll)x * x % P) if (y & 1) ans = (ll)ans * x % P;
return ans;
} inline void ycl(int n) {
fac[0] = 1; for (int i = 1; i <= n; ++i) fac[i] = (ll)fac[i - 1] * i % P;
inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = (ll)(P - P / i) * inv[P % i] % P;
ifac[0] = 1; for (int i = 1; i <= n; ++i) ifac[i] = (ll)ifac[i - 1] * inv[i] % P;
}
inline int C(int x, int y) {
if (x < y) return 0;
return (ll)fac[x] * ifac[y] % P * ifac[x - y] % P;
} inline void DP() {
S = (1 << n) - 1;
dp[0][0] = 1;
for (int i = 0; i < m; ++i) {
for (int s = 0; s <= S; ++s) {
int les = S + 1 - a[i + 1] - s;
sadd(dp[i + 1][s], dp[i][s]);
for (int j = 0; j < n; ++j) if (!((s >> j) & 1))
sadd(dp[i + 1][s | (1 << j)], (ll)dp[i][s] * C(les, (1 << j) - 1) % P * fac[1 << j] % P);
// dbg("dp[%d][%d] = %d\n", i, s, dp[i][s]);
}
}
} inline void work() {
ycl(1 << n);
DP();
int ans = 0;
for (int i = 0; i <= S; ++i) {
int cnt = 0, s = i;
while (s) ++cnt, s -= lowbit(s);
if (cnt & 1) sadd(ans, P - (ll)dp[m][i] * fac[S - i] % P);
else sadd(ans, (ll)dp[m][i] * fac[S - i] % P);
// dbg("dp[%d][%d] = %d, cnt = %d, %lld\n", m, i, dp[m][i], cnt, (ll)dp[m][i] * fac[S - i] % P);
}
ans = (ll)ans * (S + 1) % P;
printf("%d\n", ans);
} inline void init() {
read(n), read(m);
for (int i = 1; i <= m; ++i) read(a[i]);
std::reverse(a + 1, a + m + 1);
} int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}

ARC093F Dark Horse 容斥原理+DP的更多相关文章

  1. ARC093F Dark Horse 【容斥,状压dp】

    题目链接:gfoj 神仙计数题. 可以转化为求\(p_1,p_2,\ldots,p_{2^n}\),使得\(b_i=\min\limits_{j=2^i+1}^{2^{i+1}}p_j\)都不属于\( ...

  2. arc093F Dark Horse

    我们可以假设1的位置在1,并且依次与右边的区间合并.答案最后乘上2^n即可. 那么需要考虑1所在的区间与另一个区间合并时,另一个区间的最小值不能为特殊的. 直接求解很难,考虑容斥,钦定在哪几个位置必定 ...

  3. [AtCoder ARC093F]Dark Horse

    题目大意:有$2^n$个人,每相邻的两个人比赛一次.令两个人的编号为$a,b(a\leqslant b)$,若$a\neq 1$,则$a$的人获胜:否则若$b\in S$则$b$获胜,不然$1$获胜. ...

  4. 【arc093f】Dark Horse(容斥原理,动态规划,状态压缩)

    [arc093f]Dark Horse(容斥原理,动态规划,状态压缩) 题面 atcoder 有 \(2^n\) 名选手,编号为 \(1\) 至 \(2^n\) .现在这 \(2^n\) 名选手将进行 ...

  5. ARC 093 F Dark Horse 容斥 状压dp 组合计数

    LINK:Dark Horse 首先考虑1所在位置. 假设1所在位置在1号点 对于此时剩下的其他点的方案来说. 把1移到另外一个点 对于刚才的所有方案来说 相对位置不变是另外的方案. 可以得到 1在任 ...

  6. Atcoder Regular Contest 093 D - Dark Horse(组合数学+状压 dp)

    Atcoder 题面传送门 & 洛谷题面传送门 常规题,简单写写罢((( 首先 \(1\) 的位置是什么不重要,我们不妨钦定 \(1\) 号选手最初就处在 \(1\) 号位置,最后答案乘个 \ ...

  7. [CF245H] Queries for Number of Palindromes (容斥原理dp计数)

    题目链接:http://codeforces.com/problemset/problem/245/H 题目大意:给你一个字符串s,对于每次查询,输入为一个数对(i,j),输出s[i..j]之间回文串 ...

  8. 2018.07.13 [HNOI2015]落忆枫音(容斥原理+dp)

    洛谷的传送门 bzoj的传送门 题意简述:在DAG中增加一条有向边,然后询问新图中一共 有多少个不同的子图为"树形图". 解法:容斥原理+dp,先考虑没有环的情况,经过尝试不难发现 ...

  9. TC SRM498 Div1 1000PT(容斥原理+DP)

    [\(Description\)] 网格中每步可以走\((0,\cdots M_x,0\cdots M_y)\)中任意非零向量,有\(K\)种向量不能走,分别是\((r_1,r_1),(r_2,r_2 ...

随机推荐

  1. Android逆向之旅---解析编译之后的Dex文件格式

    一.前言 新的一年又开始了,大家是否还记得去年年末的时候,我们还有一件事没有做,那就是解析Android中编译之后的classes.dex文件格式,我们在去年的时候已经介绍了: 如何解析编译之后的xm ...

  2. RabbitMQ生产者消费者模型构建(三)

    ConnectionFactory:获取连接(地址,端口号,用户名,密码,虚拟主机等) Connection:一个连接 Channel:数据通信信道,可发送.接收消息 Queue:具体的消息存储队列 ...

  3. LintCode之两两交换链表中的节点

    题目描述: 我的思路: 由题目描述可知,题目是要求将第一个与第二个节点,第三个与第四节点....进行交换,而进行交换时只用将节点的值进行交换即可.需要注意的是:当链表为null或者当链表只有一个节点时 ...

  4. EZOJ #373排序

    分析 它居然真的是个nlog^3暴力?! 两个数在加小于min(lowbit(x),lowbit(y))的数时对他们的奇偶性不影响 因此每次加上min(lowbit(x),lowbit(y))判断此时 ...

  5. JSP_01

    1.定义局部变量.输出语句 <!doctype html> <html> <head> <title>定义局部变量.输出语句</title> ...

  6. C# 压缩、解压缩

    /// <summary> /// 压缩文件 FNameArry 为客户端传回来的文件列表:文件名数组,压缩包的名称strZipName /// </summary> /// ...

  7. jmeter 非GUI执行测试,没有响应数据保存到jtl文件办法

    估计是jmeter为了减轻客户机负担,就没又默认把这些信息保存,如果想要保存,也可以,需要做出如下配置: 修改bin目录下的user.properties文件,追加配置: jmeter.save.sa ...

  8. 细聊Spring Cloud Bus

    细聊Spring Cloud Bus Spring 事件驱动模型 因为Spring Cloud Bus的运行机制也是Spring事件驱动模型所以需要先了解相关知识点: 上面图中是Spring事件驱动模 ...

  9. Redis数据库-基础篇

    Redis Redis是一个开源的,先进的key-value存储. 它通常被称为数据结构服务器,因为键可以包含字符串,哈希,链表,集合和有序集合. Redis 简介 Redis 是完全开源免费的,遵守 ...

  10. kafaka环境搭建

    激动无比,终于成功搭建了一套集群的kafka,记录下我的搭建步骤,供大家参考,如有不对,请指正: 1.集群搭建 首先搭建一个一主三从(或一主两从)的集群, 2.配置jdk环境 需要是jdk8的包 我的 ...