Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/fontdata.js

BZOJ - Problem 3622 - 已经没有什么好害怕的了

题意:

  给定两个序列ab,让它们进行匹配,求出使得a_i > b_j的个数比a_i < b_j的个数恰好多k,求这样的匹配方法数

题解:

  这题的各种表示有一点相似又截然不同,很容易混淆。

  直接求恰好满足k对不好求,所以先放宽条件,这样子有利于构造动规方程。

  先用f_{i, j}表示在前i个中,至少选择ja > b的匹配的方案数(是匹配的方案数,只关心匹配那一部分,不关心其它的部分),容易得到动规方程:

                     ƒi,jƒi - 1,j + (Lasti - (j - 1)) * ƒi - 1,j - 1

  其中Last_i表示第一个小于a_ib_j

  (Last_i - (j - 1))表示原有Last_i种选择,被选走了j - 1种,此时因为是“至少”,所以其它的匹配是不用管的。

  那么现在考虑求出恰好为k的方案数。

  首先令g_i表示前Na中,满足至少有ia > b的方案数,那么

                      giƒN,j * (N - i) !

  这时候才考虑了其它的部分,所以需要乘上阶乘。

  再令f'_i表示恰好满足i组的方案数,那么考虑容斥,在所有的g_j中,每个f'_i (i > j)被算了C_i^j次,因为不考虑其它的,仅i个已匹配好的任意取j个,其它的随便排,正好被g_j囊括,当然这一部分是多余的,所以

                      ƒ'i = gj - Cj, i * ƒ'j (j > i)

代码:

 

复制代码
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 
 6 #define MOD 1000000009
 7 
 8 using namespace std;
 9 
10 typedef long long LL;
11 
12 const int MAXN = 2000 + 10;
13 
14 LL g[MAXN][MAXN];
15 
16 LL f[MAXN]= {0};
17 
18 LL fac[MAXN];
19 LL C[MAXN][MAXN];
20 
21 int N, K;
22 
23 int Candy[MAXN], Pill[MAXN];
24 
25 int Last[MAXN]= {0};
26 
27 void Preparation () {
28     fac[0] = 1;
29     for (int i = 1; i <= N; i ++)
30         fac[i] = fac[i - 1] * i % MOD;
31     
32     for (int i = 0; i <= N; i ++)
33         C[i][0] = 1;
34     for (int i = 1; i <= N; i ++)
35         for (int j = 1; j <= i; j ++)
36             C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
37 }
38 
39 int main () {
40     scanf ("%d%d", & N, & K);
41     
42     Preparation ();
43     
44     for (int i = 1; i <= N; i ++)
45         scanf ("%d", & Candy[i]);
46     for (int i = 1; i <= N; i ++)
47         scanf ("%d", & Pill[i]);
48     
49     sort (Candy + 1, Candy + N + 1);
50     sort (Pill + 1, Pill + N + 1);
51     
52     for (int i = 1; i <= N; i ++)
53         for (int j = N; j >= 1; j --)
54             if (Pill[j] < Candy[i]) {
55                 Last[i] = j;
56                 break;
57             }
58     
59     for (int i = 0; i <= N; i ++)
60         g[i][0] = 1;
61     for (int i = 1; i <= N; i ++)
62         for (int j = 1; j <= i; j ++)
63             g[i][j] = (g[i - 1][j] + (Last[i] - j + 1) * g[i - 1][j - 1] % MOD) % MOD;
64     
65     for (int i = N; i >= 1; i --) {
66         f[i] = g[N][i] * fac[N - i] % MOD;
67         for (int j = i + 1; j <= N; j ++)
68             f[i] = ((f[i] - C[j][i] * f[j] % MOD) % MOD + MOD) % MOD;
69     }
70     
71     printf ("%lld\n", f[(N + K) >> 1]);
72     
73     return 0;
74 }
75 
76 /*
77 4 2
78 5 35 15 45
79 40 20 10 30
80 */
View Code
复制代码

 

posted @   Colythme  阅读(151)  评论(0编辑  收藏  举报
编辑推荐:
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
阅读排行:
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束
欢迎阅读『BZOJ』
点击右上角即可分享
微信分享提示