【BZOJ3622】已经没有什么好害怕的了【计数DP】【姿势】
2016-04-23 08:39
405 查看
【题目链接】
【dyllalala的题解】
说下我个人的理解...
先把两个数组排序,设next[i]表示满足第i个糖果>第j个药片的最大的j。显然这个next是单调的,可以O(n)求出。
设dp[i][j]表示前i个糖果里,至少有j组糖果>药片(即这j组以外的其他情况都不考虑)的方案数。考虑第i个糖果,有两种转移:
(1)不管,dp[i][j] = dp[i - 1][j]
(2)组成一组关系,dp[i][j] = dp[i - 1][j - 1] * (next[i] - j + 1)
然后我们就求出了dp[i][j]。
现在考虑重复的情况:我们要从“至少”求出“恰好”。
设f[j]表示n个糖果里,恰好有j组糖果>药片(显然其他组都是药片>糖果)的方案数。那么有
f[j] = dp
[j] * (n - j)! - ∑(f[i] * C(i, j)),j + 1 <= i <= n
前一项是后面n - j组的总方案,后一项是分别把“至少”多出来的每一项减去。
圆神的三个题终于做完了
/* Pigonometry */
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 2005, p = 1000000009;
int n, k, A[maxn], B[maxn], next[maxn];
LL C[maxn][maxn], fact[maxn], dp[maxn][maxn];
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
int main() {
n = iread(); k = iread();
if((n - k) & 1) {
printf("0\n");
return 0;
}
k = (n + k) >> 1;
fact[0] = 1;
for(int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % p;
for(int i = 0; i <= n; i++) {
C[i][0] = 1;
for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p;
}
for(int i = 1; i <= n; i++) A[i] = iread();
for(int i = 1; i <= n; i++) B[i] = iread();
sort(A + 1, A + 1 + n); sort(B + 1, B + 1 + n);
for(int i = 1, j = 0; i <= n; next[i++] = j)
for(; j < n && A[i] > B[j + 1]; j++);
dp[0][0] = 1;
for(int i = 1; i <= n; i++) {
dp[i][0] = 1;
for(int j = 1; j <= i; j++)
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (next[i] - j + 1) % p) % p;
}
for(int i = n; i >= k; i--) {
dp
[i] = dp
[i] * fact[n - i] % p;
for(int j = i + 1; j <= n; j++)
dp
[i] = (dp
[i] - dp
[j] * C[j][i] % p + p) % p;
}
printf("%lld\n", dp
[k]);
return 0;
}
【dyllalala的题解】
说下我个人的理解...
先把两个数组排序,设next[i]表示满足第i个糖果>第j个药片的最大的j。显然这个next是单调的,可以O(n)求出。
设dp[i][j]表示前i个糖果里,至少有j组糖果>药片(即这j组以外的其他情况都不考虑)的方案数。考虑第i个糖果,有两种转移:
(1)不管,dp[i][j] = dp[i - 1][j]
(2)组成一组关系,dp[i][j] = dp[i - 1][j - 1] * (next[i] - j + 1)
然后我们就求出了dp[i][j]。
现在考虑重复的情况:我们要从“至少”求出“恰好”。
设f[j]表示n个糖果里,恰好有j组糖果>药片(显然其他组都是药片>糖果)的方案数。那么有
f[j] = dp
[j] * (n - j)! - ∑(f[i] * C(i, j)),j + 1 <= i <= n
前一项是后面n - j组的总方案,后一项是分别把“至少”多出来的每一项减去。
圆神的三个题终于做完了
/* Pigonometry */
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 2005, p = 1000000009;
int n, k, A[maxn], B[maxn], next[maxn];
LL C[maxn][maxn], fact[maxn], dp[maxn][maxn];
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
int main() {
n = iread(); k = iread();
if((n - k) & 1) {
printf("0\n");
return 0;
}
k = (n + k) >> 1;
fact[0] = 1;
for(int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % p;
for(int i = 0; i <= n; i++) {
C[i][0] = 1;
for(int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p;
}
for(int i = 1; i <= n; i++) A[i] = iread();
for(int i = 1; i <= n; i++) B[i] = iread();
sort(A + 1, A + 1 + n); sort(B + 1, B + 1 + n);
for(int i = 1, j = 0; i <= n; next[i++] = j)
for(; j < n && A[i] > B[j + 1]; j++);
dp[0][0] = 1;
for(int i = 1; i <= n; i++) {
dp[i][0] = 1;
for(int j = 1; j <= i; j++)
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * (next[i] - j + 1) % p) % p;
}
for(int i = n; i >= k; i--) {
dp
[i] = dp
[i] * fact[n - i] % p;
for(int j = i + 1; j <= n; j++)
dp
[i] = (dp
[i] - dp
[j] * C[j][i] % p + p) % p;
}
printf("%lld\n", dp
[k]);
return 0;
}
相关文章推荐
- 【013】【内存调优】
- ubuntu emacs setup
- CodeForces 9B Running Student
- mysql ICP和MRR性能优化测试
- SQL Server 2008 r2出现无法连接到服务器和服务器积极拒绝两个问题
- vimrc for debian8
- tolua++没法用
- tolua++没法用
- CodeForces 9A Die Roll
- unity中的jsp函数 控制角色移动transform.Translate
- 练习2————1003
- ClassLoader机制分析与自制加解、密类加载器
- poj 1321 棋盘问题
- JSON学习笔记
- centos7的initrd.img解压缩
- libcurl网络连接使用tcp/ip
- 【BZOJ 1832】 [AHOI2008]聚会|倍增lca
- 印度储备银行行长批评央行,关注数字货币追赶中国
- FreeRTOS学习笔记
- Flex Library ANT 编译