Portal

题意:

给出两个序列 \(a_1,a_2,\dots,a_n\),\(b_1,b_2,\dots,b_n\),\(i\) 与 \(j\) 能匹配当且仅当 \(a_i\leq b_j\)。

定义一个匹配是极大的,当且仅当对于匹配的 \((i,j)\) 都有 \(a_i\leq b_j\) 并且未被匹配的 \(a_i,b_j\) 两两无法匹配。

求极大匹配的个数 \(\bmod(10^9+7)\)。

\(1\leq n\leq 3000\)

真·Pt 三个 \(\bmod (10^9+7)\)。

真·去年 Pt bao0 今年还是 bao0

我还有什么好说的呢?/kk

现场只会 \(n^3\) 的做法,赛后看了题解才发现我们做法里正解只差一步之遥。

显然,一个匹配是极大匹配的充要条件是最小的未被匹配的 \(a_i\) \(\gt\) 最大的未被匹配的 \(b_j\)。

\(a,b\) 的下标对匹配个数显然是没有影响的,故不管三七二十一先将 \(a,b\) 从小到大排个序。

定义 \(p_j\) 为最大的满足 \(a_i\leq b_j\) 的 \(i\)。那么 \(j\) 能匹配的 \(a_i\) 是 \(a\) 的一段前缀——一段长度为 \(p_j\) 的前缀。那么这样一来,每个 \(b_j\) 有两种选择,一种是选择一个下标 \(\leq p_j\) 的,被钦定“要被匹配”却还没有被匹配的 \(a_i\) 并与其进行匹配。一种是干脆不匹配。但是,如果在 \(1\)~\(p_j\) 中存在某个 \(a_i\) 被钦定“不被匹配”,那么就不能选择第二种情况。因为这样一来就会存在一个未被匹配的 \(a_i\leq b_j\),不符合极大匹配的条件。

我们可以因此设计出 \(dp\) 状态:\(dp_{i,x,f}\) 表示我们在前 \(p_i\) 个 \(a_i\) 和前 \(i\) 个 \(b_j\) 中匹配 ,现在有 \(x\) 个 \(a_i\) 被钦定“要被匹配”却还没有被匹配,\(f\) 表示是否存在某个 \(a_i\) 被钦定“不被匹配”。考虑 \((p_i,p_{i+1}]\) 中的 \(a_i\),我们枚举其当中被钦定“要被匹配”的个数 \(k\),然后可以得到下面两个转移方程式:

  • \(dp_{i+1,x+k-1,f|(k!=(p_{i+1}-p_i))}+=dp_{i,j,k}\times \binom{p_{i+1}-p_i}{k}\times(x+k)\)
  • \(dp_{i+1,x+k,f|(k!=(p_{i+1}-p_i))}+=dp_{i,j,k}\times \binom{p_{i+1}-p_i}{k}\) 这种转移要求 \(f|(k!=(p_{i+1}-p_i))=0\)

稍微解释一下这两个转移方程:第一个方程对应上面的第一种情况,从 \(p_{i+1}-p_i\) 个 \(a_i\) 当中钦定选择 \(k\) 个的方案数为 \(\binom{p_{i+1}-p_i}{k}\),再选择一个与 \(b_{i+1}\) 匹配有 \(x+k\) 种选法。第二个方程对应上面的第二种情况,即 \(b_{i+1}\) 不与任何 \(a_i\) 匹配。但这种转移有个前提条件,那就是 \([1,p_{i+1}]\) 中所有的 \(a_i\) 都要被钦定匹配,即 \(f|(k!=(p_{i+1}-p_i))=0\)。

最终答案即为 \(dp_{n,0,0}+dp_{n,0,1}\)。时间复杂度乍一看是 \(n^3\) 的,但 \(\sum p_{i+1}-p_i=n\),故转移均摊 \(\mathcal O(1)\),总复杂度 \(\mathcal O(n^2)\)。

看到没?什么超纲的算法都没有。所以啊,菜是原罪/kk

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=3000;
const int MOD=1e9+7;
int n,a[MAXN+5],b[MAXN+5],p[MAXN+5],dp[MAXN+5][MAXN+5][2],c[MAXN+5][MAXN+5];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);sort(a+1,a+n+1);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);sort(b+1,b+n+1);
for(int i=0;i<=MAXN;i++){
c[i][0]=1;
for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
int pos=1;
for(int i=1;i<=n;i++){
while(pos<=n&&a[pos]<=b[i]) pos++;
p[i]=--pos;
}
dp[0][0][0]=1;
for(int i=0;i<n;i++) for(int j=0;j<=p[i];j++){
for(int k=0;k<2;k++) for(int l=0;l<=p[i+1]-p[i];l++){
int nk=(k||(l!=(p[i+1]-p[i])));
if(j+l-1>=0) dp[i+1][j+l-1][nk]=(dp[i+1][j+l-1][nk]+1ll*dp[i][j][k]*(j+l)%MOD*c[p[i+1]-p[i]][l]%MOD)%MOD;
if(!nk) dp[i+1][j+l][nk]=(dp[i+1][j+l][nk]+1ll*dp[i][j][k]*c[p[i+1]-p[i]][l])%MOD;
}
}
// for(int i=1;i<=n;i++) for(int j=0;j<=p[i];j++) for(int k=0;k<2;k++)
// printf("%d %d %d %d\n",i,j,k,dp[i][j][k]);
printf("%d\n",(dp[n][0][0]+dp[n][0][1])%MOD);
return 0;
}

洛谷 P7154 - [USACO20DEC] Sleeping Cows P(dp)的更多相关文章

  1. 洛谷P3047 [USACO12FEB]Nearby Cows(树形dp)

    P3047 [USACO12FEB]附近的牛Nearby Cows 题目描述 Farmer John has noticed that his cows often move between near ...

  2. 洛谷 P7155 [USACO20DEC] Spaceship P(dp)

    Portal Yet another 1e9+7 Yet another 计数 dp Yet another 我做不出来的题 考虑合法的按键方式长啥样.假设我们依次按下了 \(p_1,p_2,\dot ...

  3. 【POJ3621】【洛谷2868】Sightseeing Cows(分数规划)

    [POJ3621][洛谷2868]Sightseeing Cows(分数规划) 题面 Vjudge 洛谷 大意: 在有向图图中选出一个环,使得这个环的点权\(/\)边权最大 题解 分数规划 二分答案之 ...

  4. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

  5. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  6. 洛谷 P4072 [SDOI2016]征途 斜率优化DP

    洛谷 P4072 [SDOI2016]征途 斜率优化DP 题目描述 \(Pine\) 开始了从 \(S\) 地到 \(T\) 地的征途. 从\(S\)地到\(T\)地的路可以划分成 \(n\) 段,相 ...

  7. 洛谷P1880 石子合并(区间DP)(环形DP)

    To 洛谷.1880 石子合并 题目描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分. 试设计出1 ...

  8. 洛谷P1063 能量项链(区间DP)(环形DP)

    To 洛谷.1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的 ...

  9. 洛谷P1282 多米诺骨牌 (DP)

    洛谷P1282 多米诺骨牌 题目描述 多米诺骨牌有上下2个方块组成,每个方块中有1~6个点.现有排成行的 上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|.例如在图8-1中 ...

随机推荐

  1. Spark分区器浅析

    分区器作用:决定该数据在哪个分区 概览: 仅仅只有pairRDD才可能持有分区器,普通RDD的分区器为None 在分区器为None时RDD分区一般继承至父RDD分区 初始RDD分区数: 由集合创建,R ...

  2. 036—环境变量path

    day04 课堂笔记 1.开发第一个java程序:HelloWorld 1.1.程序写完以后,一定要ctrl+s进行保存 源代码若修改,需重新进行编译 1.2.编译阶段 怎么编译?使用什么命令?这个命 ...

  3. vue3.x移动端页面基于vue-router的路由切换动画

    移动端页面切换一般都具有动画,我们既然要做混合开发,做完之后还是不能看起来就像一个网页,所以我们基于vue-router扩展了一个页面切换push和pop的动画.这是一篇比较硬核的帖子,作者花了不少精 ...

  4. 敏捷 Scrum Master 的難點

    什麼是 Scrum Master? Scrum master 是一個團隊角色,負責確保團隊遵守敏捷方法和原則並符合團隊的流程和實踐. Scrum Master 促進敏捷開發團隊成員之間的協作.Scru ...

  5. 2019OO第四单元作业总结&OO课程整体总结

    第四单元作业总结 第四单元的作业主题是UML图的解析,通过对UML图代码的解析,我对UML图的结构以及各种元素之间的关系的理解更加深入了. ------------------------------ ...

  6. spring security实现简单的url权限拦截

    在一个系统中,权限的拦截是很常见的事情,通常情况下我们都是基于url进行拦截.那么在spring security中应该怎么配置呢. 大致步骤如下: 1.用户登录成功后我们需要拿到用户所拥有的权限,并 ...

  7. 第32篇-解析interfacevirtual字节码指令

    在前面介绍invokevirtual指令时,如果判断出ConstantPoolCacheEntry中的_indices字段的_f2属性的值为空,则认为调用的目标方法没有连接,也就是没有向Constan ...

  8. Zabbix 5.0:监控阿里云RDS

    Blog:博客园 个人 由于近期压测,需要频繁登录阿里云查看RDS监控,每次登录查看监控步骤较为繁琐,故将监控接入到zabbix. 概述 由于阿里云已做了RDS的监控,我们只需要通过阿里云SDK把这些 ...

  9. 【学习笔记】Vizing 定理

    图染色问题的经典结论 定义 称一个边染色方案合法当且仅当每个顶点连出的所有边的颜色都互不相同,如果此时出现了 \(k\) 个颜色那么称该方案是图的一组 \(k\) 染色 一张无向图的边着色数为最小的 ...

  10. Python课程笔记 (五)

    今天主要学习图形用户界面,更多的还是要我们自己去实际操作,课仿佛上了一半就完了,分享一下课程(这里在SixthClass)的源码: https://gitee.com/wang_ming_er/pyt ...