BZOJ3622 已经没有什么好害怕的了 【dp + 二项式反演】
题目链接
题解
既已开题
那就已经没有什么好害怕的了
由题目中奇怪的条件我们可以特判掉\(n - k\)为奇数时答案为\(0\)
否则我们要求的就是糖果大于药片恰好有\(\frac{n - k}{2} + k\)个的方案数,我们记为\(K\)
思路1##
直接求恰好不好求,想到二项式反演:
如果有
\]
那么有
\]
如果我们令\(a_k\)为恰好有\(K\)对糖果大于药片的方案数
从式子来看,对于每一种\(a_i\)的情况,\(b_k\)都从中选出任意\(k\)个
那么\(b_k\)就是任选\(k\)个满足条件,剩余随便选的方案数
问题就转化为了求出\(b_k\),显然可以\(dp\)
我们先将糖果与药片分别升序排序
我们设\(f[i][j]\)表示前\(i\)个糖果选出\(j\)个和药片匹配,都大于药片的方案数
我们记\(pos_i\)为第\(i\)个糖果比药片大的最大的位置,那么如果第\(i\)个糖果参与匹配,就有\(pos_i\)种选择
由于糖果是升序排序,所以剩余\(j - 1\)个糖果选择范围一定不比\(i\)大,所以\(i\)实际剩余\(pos_i - (j - 1)\)种选择
那么有
\]
求出\(f[n][i]\),则\(b_k = f[n][k] * (n - k)!\)
然后再用二项式反演即可求出\(a_k\)
思路2##
如果你不知道二项式反演,其实有一个更直观的方法
同样是求出\(f[n][i]\)后求出\(b_i\)
我们令\(ans[k]\)表示恰好\(k\)个糖果大于药片的方案数
显然
\]
当\(k < n\)时,\(b_k\)多算了恰好为\(k + 1\)、\(k + 2\)、\(k + 3......\)的方案数,减去即可
\]
这样也是对的
PS##
由思路2其实我们可以看到二项式反演实际上就是一个容斥的结果
思路一
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 2005,maxm = 100005,INF = 1000000000,P = 1000000009;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
LL f[maxn][maxn],C[maxn][maxn],fac[maxn];
int a[maxn],b[maxn];
int n,K;
void init(){
fac[0] = 1;
for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % P;
for (int i = 0; i <= n; i++){
C[i][0] = C[i][i] = 1;
for (int j = 1; j <= (i >> 1); j++)
C[i][j] = C[i][i - j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
sort(a + 1,a + 1 + n);
sort(b + 1,b + 1 + n);
}
int main(){
n = read(); K = read();
if ((n - K) & 1) {puts("0"); return 0;}
K = ((n - K) >> 1) + K;
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) b[i] = read();
init();
f[0][0] = 1;
for (int i = 1; i <= n; i++){
f[i][0] = f[i - 1][0];
int pos = n;
while (pos && b[pos] >= a[i]) pos--;
for (int j = 1; j <= i; j++)
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * max(pos - j + 1,0) % P) % P;
}
LL ans = 0,t;
for (int i = K; i <= n; i++){
t = ((i - K) & 1) ? -1 : 1;
ans = ((ans + t * C[i][K] % P * (f[n][i] * fac[n - i] % P) % P) % P + P) % P;
}
printf("%lld\n",ans);
return 0;
}
思路2
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 2005,maxm = 100005,INF = 1000000000,P = 1000000009;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
LL f[maxn][maxn],C[maxn][maxn],fac[maxn],ans[maxn];
int a[maxn],b[maxn];
int n,K;
void init(){
fac[0] = 1;
for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % P;
for (int i = 0; i <= n; i++){
C[i][0] = C[i][i] = 1;
for (int j = 1; j <= (i >> 1); j++)
C[i][j] = C[i][i - j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
sort(a + 1,a + 1 + n);
sort(b + 1,b + 1 + n);
}
int main(){
n = read(); K = read();
if ((n - K) & 1) {puts("0"); return 0;}
K = ((n - K) >> 1) + K;
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1; i <= n; i++) b[i] = read();
init();
f[0][0] = 1;
for (int i = 1; i <= n; i++){
f[i][0] = f[i - 1][0];
int pos = n;
while (pos && b[pos] >= a[i]) pos--;
for (int j = 1; j <= i; j++)
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * max(pos - j + 1,0) % P) % P;
}
ans[n] = f[n][n];
for (int i = n - 1; i >= K; i--){
ans[i] = f[n][i] * fac[n - i] % P;
for (int j = i + 1; j <= n; j++)
ans[i] = (ans[i] - C[j][i] * ans[j] % P) % P;
ans[i] = (ans[i] + P) % P;
}
printf("%lld\n",ans[K]);
return 0;
}
BZOJ3622 已经没有什么好害怕的了 【dp + 二项式反演】的更多相关文章
- P4859 已经没有什么好害怕的了(dp+二项式反演)
P4859 已经没有什么好害怕的了 啥是二项式反演(转) 如果你看不太懂二项式反演(比如我) 那么只需要记住:对于某两个$g(i),f(i)$ ---------------------------- ...
- bzoj3622已经没有什么好害怕的了 dp+组合+容斥(?)
3622: 已经没有什么好害怕的了 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1033 Solved: 480[Submit][Status][ ...
- [BZOJ3622] 已经没有什么好害怕的了(dp+容斥)
Description: 有两个数组a和b,两两配对,求 \(a_i>b_i\) 的配对比 \(b_i>a_i\) 的配对多 \(k\) 个的方案数 \(k\le n\le 2000\ ...
- [bzoj3622]已经没有什么好害怕的了_动态规划_容斥原理
bzoj-3622 已经没有什么好害怕的了 题目大意: 数据范围:$1\le n \le 2000$ , $0\le k\le n$. 想法: 首先,不难求出药片比糖果小的组数. 紧接着,我开始的想法 ...
- bzoj3622已经没有什么好害怕的了
bzoj3622已经没有什么好害怕的了 题意: 给n个数Ai,n个数Bi,将Ai中的数与Bi中的数配对,求配对Ai比Bi大的比Bi比Ai大的恰好有k组的方案数.n,k≤2000 题解: 蒟蒻太弱了只能 ...
- BZOJ 3622 : 已经没有什么好害怕的了(dp + 广义容斥原理)
今天没听懂 h10 的讲课 但已经没有什么好害怕的了 题意 给你两个序列 \(a,b\) 每个序列共 \(n\) 个数 , 数之间两两不同 问 \(a\) 与 \(b\) 之间有多少配对方案 使得 \ ...
- luoguP4859 已经没有什么好害怕的了(二项式反演)
luoguP4859 已经没有什么好害怕的了(二项式反演) 祭奠天国的bzoj. luogu 题解时间 先特判 $ n - k $ 为奇数无解. 为了方便下记 $ m = ( n + k ) / 2 ...
- [BZOJ3622]已经没有什么好害怕的了(容斥DP)
给定两个数组a[n]与b[n](数全不相等),两两配对,求“a比b大”的数对比“b比a大”的数对个数多k的配对方案数. 据说做了这题就没什么题好害怕的了,但感觉实际上这是一个套路题,只是很难想到. 首 ...
- BZOJ3622 已经没有什么好害怕的了 动态规划 容斥原理 组合数学
原文链接https://www.cnblogs.com/zhouzhendong/p/9276479.html 题目传送门 - BZOJ3622 题意 给定两个序列 $a,b$ ,各包含 $n$ 个数 ...
随机推荐
- 牛客小白月赛2 H 武 【Dijkstra】
链接:https://www.nowcoder.com/acm/contest/86/H来源:牛客网 题目描述 其次,Sεlιнα(Selina) 要进行体力比武竞赛. 在 Sεlιнα 所在的城市, ...
- 【PE】手动给PE文件添加一段代码MessageBoxA
源程序是这个样子: 思路: 1.通过LordPE工具拿到所需数据 2.OllyDebug通过BP MessageBoxA拿到MessageBoxA地址 3.UE十六进制编辑器定位代码节基址 4.在代码 ...
- 基于mybatis设计简单OA系统问题2
1.<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <fm ...
- Nginx+php+mysql+wordpress搭建自己的博客站点
服务器环境要求Centos 6 或以上版本(由于我们的目标是半小时内搭建好,那就选简单yum安装)MySQL 5或更新版本Nginx 1或更新版本PHP 5 或更新版本 php-fpm 5或更新版本 ...
- python--Matplotlib(二)
Matplotlib+pandas作图 一.对csv文件进行提取ruixi.csv 对上述表格进行提取并做图 #-*- coding:utf-8 -*- import matplotlib as mp ...
- 内置函数系列之 filter
filter 过滤 基本语法: s = filter(function,iterable) 将可迭代对象的每一个元素,传进函数中,根据函数中的判断条件,返回True或False 返回True的是保留的 ...
- linux学习(2)——文件和目录管理
(二) 一:绝对路径和相对路径 ...
- 对文件 I/O,标准 I/O 的缓冲的理解
1.标准I/O缓冲区 要理解标准I/O,就要先知道文件I/O的业务逻辑. 下面图示为文件I/O 如执行下面的代码: write(fd, buf2, sizeof(buf2)); 图中 buf:就是bu ...
- 可以字符串string转化成list,tuple,dict的eval()方法
功能:将字符串str当成有效的表达式来求值并返回计算结果. 语法: eval(source[, globals[, locals]]) -> value 参数: source:一个Python表 ...
- Android面试收集录6 事件分发机制
转自:秋招面试宝典. 一. 基础认知 1.1 事件分发的对象是谁? 答:事件 当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件). Touch事件相关细节(发 ...