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 ...
随机推荐
- Linux的磁盘分区
大于2T分区 Linux-GCAPP1:/ # parted /dev/sdb GNU Parted 2.3 Using /dev/sdb Welcome to GNU Parted! Type 'h ...
- 【CF1243B2】Character Swap (Hard Version)【思维】
题意:给定两个字符串,问是否存在交换方案使得两个字符串相同,方案为交换次数小于等于2n,且每次只交换s1与s2中的一个字符 题解:考虑从前往后枚举,当第i位不同时,考虑找后边的第j位,若存在这样的第j ...
- ASP汉字转拼音函数的方法
<% 'ASP汉字转拼音函数 Set d = CreateObject("Scripting.Dictionary") d.add "a",-20319 ...
- 秒杀Servlce接口设计
秒杀Servlce接口设计 1.创建service包,创建SecKillServlce业务接口 SecKillServlce.Java package org.secKill.service;/** ...
- Windows定时任务+bat文件+WinRar处理Mysql数据库的定时自动备份
服务器环境 Windows Server 2003 ,服务器上采用的是IIS+mysql的集成工具phpStudy.MySQL的安装目录D:\phpStudy4IIS , WinRAR 安装目录 C: ...
- scrapy--meta参数传递问题
scrapy使用大坑---meta参数传递出现之重复问题 问题描述: 爬虫目标: 实现哔哩哔哩网站的视频信息爬取,只要的信息结构爬去顺序为**关键词的搜索结果,拿到第一页上某个视频的标题,url,和时 ...
- CDN:BootCDN
ylbtech-CDN:BootCDN BootCDN稳定.快速.免费的前端开源项目 CDN 加速服务共收录了 3351 个前端开源项目 1. 推荐返回顶部 1. bootstrap Bootstra ...
- Linux 两台服务器之间传递文件
参考: https://www.cnblogs.com/clovershell/p/9870603.html linux采用scp命令拷贝文件到本地,拷贝本地文件到远程服务器 // 假设远程服务器 ...
- postgresql中实现按周统计详解
SELECT EXTRACT(DOW FROM CURRENT_DATE); 执行结果如下. 这个SQL语句的意思就是计算当前日期是一周中的第几天. EXTRACT(DOW FROM CURREN ...
- sts测试流程
测试目的: 测试安全补丁打上了没 测试前提: 1.发货版本,user debug版本,相应安全补丁已合入,测试工具与安全补丁是对应的 2.selinux:Enable 3.连接ADB,stay awa ...