JOISC2020 遗迹
Description
给定一个有 个建筑的街道,建筑的高度的多重集等于多重集
会发生 次地震,每次地震会使得每个高度 的建筑中非最右侧建筑的高度减少 ,减至 则不再减
最后有 个高度为 的建筑会被保留,给定位置集合,求有多少初始高度排列能得到呢?
Solution
设每个数字第一次出现为 第二次出现类似的为
考虑给定一组 求得最后的 的过程,以下两种是等价的
-
从 到 扫每个 ,维护集合 ,初始为空,每次将 并弹出最大元素作为这个位置最后保留的 ,那么得到的 就是所有 的并集
-
从 到 扫描每个位置,维护长度为 的序列 初始为全 ,对于 找到 仍为 的 并将 置为
我只想到了第一个过程所以这题没得做,执行第二个过程并设 表示从后往前走到了 ,前面的放置满足 的方案数,初始化 ,答案为
讨论 是否属于题目中所给的 有两种转移,设 的数量为 , 中不在 中的数字数量为 ,简记 :
-
时比较容易,这时候 的取值只能是 否则会让 增加,那么 贡献给 的系数是没有被两次放置的数字,形式化表示为
-
时分 与否进行讨论,如果 时不会对第二维造成变化,先
如果 枚举 贡献到的 首先选出来 个数字中的 个最后变成了 (左边是开区间的原因是 这些被选的点的下标 ),即先附加
同时将高度为 的两根柱子看作是本质不同的柱子来转移,最后除 ,不难发现这和 的转移是吻合的,所以这时候 的取值有 种即 中的一个或者 的两个
剩下的就考虑 个数字分配高度使得最终形成长度为 的连续段的方案数
朴素的 dp 的做法就是 表示 个位置填 的数字并使其合法的方案数,那么
含义就是在高度 填 个柱子,这里注意每个高度都有两个本质不同的柱子了所以要在 处乘 即 的系数 也乘
预处理即可
时间复杂度
Code
const int N=1210;
int n,dp[N][N],suf[N],fac[N],ifac[N],f[N];
inline int C(int n,int m){return mul(fac[n],mul(ifac[m],ifac[n-m]));}
bool vis[N];
signed main(){
f[0]=fac[0]=1;
rep(i,1,1200) fac[i]=mul(fac[i-1],i);
ifac[1200]=ksm(fac[1200],mod-2);
Down(i,1200,1) ifac[i-1]=mul(ifac[i],i);
n=read();
for(int i=1;i<=n;++i){
int pos=read();
vis[pos]=1;
f[i]=mul(fac[i+1],mul(ifac[i+2],C(2*(i+1),i+1)));
ckmul(f[i],fac[i]);
}
dp[n<<1|1][0]=1;
Down(i,2*n,1){
suf[i]=suf[i+1]+vis[i];
if(!vis[i]){
int des=2*n-i-suf[i];
for(int j=des+1;j<=suf[i];++j) dp[i][j]=mul(dp[i+1][j],j-des);
}else{
for(int j=0;j<=suf[i+1];++j) if(dp[i+1][j]){
ckadd(dp[i][j],dp[i+1][j]);
for(int k=1;j+k<=suf[i];++k){
int addi=mul(f[k-1],mul(k+1,C(suf[i+1]-j,k-1)));
ckadd(dp[i][j+k],mul(dp[i+1][j],addi));
}
}
}
}
print(mul(dp[1][n],ksm((mod+1)/2,n)));
return 0;
}
这题真的做完了吗?
另附 的简单解释
考虑 的实际含义,将 写到序列上,中间挑 个数字出来,限制 ,将有数的位置看成 ,空位置看成 那么变成了偶数位置 ,这就是卡特兰数第 项,可以用不经过直线 来理解
更直白地(来自 happyguy656):偶数位置的限制 再添加进去奇数位置 那么就都有限制了,再在序列开头加一个左括号,结尾加一个右括号就变成了偶数位置 ,奇数位置 ,就是正宗卡特兰数了,序列长度 ,所以是第 项
最后乘阶乘的原因是这 个数字是等价的,轮换也无妨
在 LOJ 讨论区里 nealchen 写了这样一个结论:长度为 的括号序列的合法子序列的数量为 ,考察了最后一个括号的匹配者并使用了 相同来证明的,有没有组合意义解释呢?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律