ARC093F Dark Horse 容斥原理+DP
题目传送门
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的更多相关文章
- 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\)都不属于\( ...
- arc093F Dark Horse
我们可以假设1的位置在1,并且依次与右边的区间合并.答案最后乘上2^n即可. 那么需要考虑1所在的区间与另一个区间合并时,另一个区间的最小值不能为特殊的. 直接求解很难,考虑容斥,钦定在哪几个位置必定 ...
- [AtCoder ARC093F]Dark Horse
题目大意:有$2^n$个人,每相邻的两个人比赛一次.令两个人的编号为$a,b(a\leqslant b)$,若$a\neq 1$,则$a$的人获胜:否则若$b\in S$则$b$获胜,不然$1$获胜. ...
- 【arc093f】Dark Horse(容斥原理,动态规划,状态压缩)
[arc093f]Dark Horse(容斥原理,动态规划,状态压缩) 题面 atcoder 有 \(2^n\) 名选手,编号为 \(1\) 至 \(2^n\) .现在这 \(2^n\) 名选手将进行 ...
- ARC 093 F Dark Horse 容斥 状压dp 组合计数
LINK:Dark Horse 首先考虑1所在位置. 假设1所在位置在1号点 对于此时剩下的其他点的方案来说. 把1移到另外一个点 对于刚才的所有方案来说 相对位置不变是另外的方案. 可以得到 1在任 ...
- Atcoder Regular Contest 093 D - Dark Horse(组合数学+状压 dp)
Atcoder 题面传送门 & 洛谷题面传送门 常规题,简单写写罢((( 首先 \(1\) 的位置是什么不重要,我们不妨钦定 \(1\) 号选手最初就处在 \(1\) 号位置,最后答案乘个 \ ...
- [CF245H] Queries for Number of Palindromes (容斥原理dp计数)
题目链接:http://codeforces.com/problemset/problem/245/H 题目大意:给你一个字符串s,对于每次查询,输入为一个数对(i,j),输出s[i..j]之间回文串 ...
- 2018.07.13 [HNOI2015]落忆枫音(容斥原理+dp)
洛谷的传送门 bzoj的传送门 题意简述:在DAG中增加一条有向边,然后询问新图中一共 有多少个不同的子图为"树形图". 解法:容斥原理+dp,先考虑没有环的情况,经过尝试不难发现 ...
- TC SRM498 Div1 1000PT(容斥原理+DP)
[\(Description\)] 网格中每步可以走\((0,\cdots M_x,0\cdots M_y)\)中任意非零向量,有\(K\)种向量不能走,分别是\((r_1,r_1),(r_2,r_2 ...
随机推荐
- Python3解leetcode Count Binary Substrings
问题描述: Give a string s, count the number of non-empty (contiguous) substrings that have the same numb ...
- 【HDOJ6693】Valentine's Day(概率)
题意:给定n件物品,每件物品让周驿东开心的概率为a[i] 要求从中选一些,使得周驿东恰好开心一次的概率最大 n<=1e4,0<=a[i]<=1 思路: #include<bit ...
- 相同name,取最小的id的值,mysql根据相同字段 更新其它字段
id name info1 a 1232 a 2353 a 1244 b 125 b 987相同name,取最小的id的值id name info1 a 1232 a 1233 a 1234 b 12 ...
- ANTLR4的IntelliJ IDEA配置
1.配置的先导工作 jdk配置 IntelliJ IDEA安装配置 配置好ANTLR的java运行时环境,参考 2.下载intellij-plugin-v4.zip 下载地址 3.插件安装 4.测试安 ...
- MySql使用mysqldump 导入与导出方法总结
导出数据库数据:首先打开cmd进入MySQL的bin文件夹下 1.导出education数据库里面的users表的表数据和表结构(下面以users表为例) mysqldump -u[用户名] -h[i ...
- __I、 __O 、__IO是什么意思?怎么用?
出处:http://www.chuxue123.com/forum.php?mod=viewthread&tid=122&ctid=3 __I. __O .__IO是什么意思?这是ST ...
- Vagrant 手册之多个虚拟机 multi-machine
原文地址 Vagrant 可以通过一个 Vagrantfile 定义并控制多个客户机.这就是所谓的"multi-machine"多虚拟机环境. 这些机器通常可以协同工作,或者互相关 ...
- 机器学习实战笔记-11-Apriori与FP-Growth算法
Apriori算法 优点:易编码实现:缺点:大数据集上较慢:适用于:数值型或标称型数据. 关联分析:寻找频繁项集(经常出现在一起的物品的集合)或关联规则(两种物品之间的关联关系). 概念:支持度:数据 ...
- python的正则
一.认识模块 什么是模块:一个模块就是一个包含了python定义和声明的文件,文件名就是加上.py的后缀,但其实import加载的模块分为四个通用类别 : 1.使用python编写的代码(.py文件 ...
- ELK日志分析系统之logstash7.x最新版安装与配置
2 .Logstash的简介 2.1 logstash 介绍 LogStash由JRuby语言编写,基于消息(message-based)的简单架构,并运行在Java虚拟机(JVM)上.不同于分离的代 ...