BZOJ - Problem 3622 - 已经没有什么好害怕的了
题意:
给定两个序列a和b,让它们进行匹配,求出使得a_i > b_j的个数比a_i < b_j的个数恰好多k,求这样的匹配方法数
题解:
这题的各种表示有一点相似又截然不同,很容易混淆。
直接求恰好满足k对不好求,所以先放宽条件,这样子有利于构造动规方程。
先用f_{i, j}表示在前i个中,至少选择j个a > b的匹配的方案数(是匹配的方案数,只关心匹配那一部分,不关心其它的部分),容易得到动规方程:
ƒi,j = ƒi - 1,j + (Lasti - (j - 1)) * ƒi - 1,j - 1
其中Last_i表示第一个小于a_i的b_j。
(Last_i - (j - 1))表示原有Last_i种选择,被选走了j - 1种,此时因为是“至少”,所以其它的匹配是不用管的。
那么现在考虑求出恰好为k的方案数。
首先令g_i表示前N个a中,满足至少有i个a > 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 */
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· langchain0.3教程:从0到1打造一个智能聊天机器人
· 2025成都.NET开发者Connect圆满结束