BZOJ5416 NOI2018冒泡排序(动态规划+组合数学)
打表可以发现相当于不存在长度>=3的递减子序列。
考虑枚举在哪一位第一次不卡限制。注意到该位一定会作为前缀最大值。判掉已确定位不合法的情况后,现在的问题即为求长度为i、首位>j的合法排列个数,设其为g[i][j]。
由于首位>j,1~j在排列中一定依次出现,并且在j出现之前,>j的部分也一定单增。于是可以先将>j的部分安排好,再将1~j不改变相对顺序地插入。>j的部分即是考虑没有各种奇怪的限制要怎么求。设f[i][j]为长度i的排列,第一个非前缀max的数在j位置的方案数。特别地,令f[i][i+1]为不存在这样的数时的方案数(当然就是1)。则有f[i][j]=Σf[i-1][k] (j-1<=k<=i+1),也即f[i][j]=f[i][j+1]+f[i-1][j-1]。这样f[i][1~i+1]即为n=i且无限制的答案,并且有了这个求g就很容易了,即考虑1~j的插入位置,有g[i][j]=Σf[i-j][k]·C(j+k-2,k-2) (k=2~i-j+1)。于是得到了一个80分的做法。给无限制时的答案打一下表又可以发现答案即为卡特兰数,可以再拿4分。
似乎有点陷入僵局。继续打表!我们惊奇的发现,g[i][j]=f[i+1][j+3]。这个式子可能是说明之前绕了太多弯,本来直接考虑怎么推g就行了,虽然这个我没想清楚也懒得考虑了。由于最终要用到的只是g中的n项,如果能快速求出f数组中任意项,问题就解决了。
考虑根据f的转移方程画一张有向图,答案即为由原点走到目标点的路径条数。
得到这样一个丑陋的图。如果要到最左的点,就是卡特兰数的经典模型。于是下面所有的分析只要类比卡特兰数就可以了。事实上这是个原题https://www.luogu.org/problemnew/show/P1641。
考虑先不管图的边界随便走,此时向右下走n步、向左走m步时的方案数显然是C(n+m,m)。加上边界后,考虑哪些走法会变得不合法,显然不合法的方案中一定存在一个第一次跨过边界的点,而这可以看做是从左上一个并不存在的点(原点向左平移两格)、以边界为对称轴、按和右边对称的走法走来的,经过此点后走法变为和右边相同。并且显然每一种从这个不存在的点到达终点的走法都对应于一种不合法方案。两个组合数相减即可。原问题也被线性解决了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 998244353
#define N 600010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<''||c>'')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int T,n,a[N],fac[N<<],inv[N<<],mn[N],ans;
int C(int n,int m){if (m<) return ;return 1ll*fac[n]*inv[m]%P*inv[n-m]%P;}
int calc(int n,int m){m=n-m;return (C(n+m,m)-C(n+m,m-)+P)%P;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5416.in","r",stdin);
freopen("bzoj5416.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
n=read();
for (int i=;i<=n;i++) a[i]=read();
fac[]=;for (int i=;i<=*n;i++) fac[i]=1ll*fac[i-]*i%P;
inv[]=inv[]=;for (int i=;i<=*n;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
for (int i=;i<=*n;i++) inv[i]=1ll*inv[i-]*inv[i]%P;
int mx=;ans=;
mn[n+]=n+;
for (int i=n;i>=;i--) mn[i]=min(mn[i+],a[i]);
for (int i=;i<=n;i++)
{
mx=max(mx,a[i]);
ans=(ans+calc(n-i+,mx-i+))%P;
if (a[i]<mx&&a[i]>mn[i+]) break;
}
printf("%d\n",ans);
}
return ;
}
BZOJ5416 NOI2018冒泡排序(动态规划+组合数学)的更多相关文章
- BZOJ_5416_[Noi2018]冒泡排序_DP+组合数+树状数组
BZOJ_5416_[Noi2018]冒泡排序_DP+组合数+树状数组 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好题. ...
- 【洛谷4769】[NOI2018] 冒泡排序(动态规划_组合数学)
题目: 洛谷 4769 博客页面左下角的嘴嘴瓜封神之战中的题目 分析: 一个排列交换次数为 \(\frac{1}{2}\sum_{i=1}^{n}|i-p_i|\) 的充要条件是这个排列不存在长度为 ...
- [NOI2018]冒泡排序
https://www.zybuluo.com/ysner/note/1261482 题面 戳我 \(8pts\ n\leq9\) \(44pts\ n\leq18\) \(ex12pts\ q_i= ...
- 【NOI 2018】冒泡排序(组合数学)
题意大概是给定一个长度为$n$的排列$p$,求有多少长度为$n$的排列满足冒泡排序的交换次数为$\frac{1}{2} \sum\limits_{i = 1}^{n}|i - p_{i}|$. 可以发 ...
- [POJ1664] 放苹果 (动态规划,组合数学)
题目描述 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分发(5,1,1和1,1,5是同一种方法) 输入输出格式 输入格式: 第一行是测试数据的数目t(0 <= ...
- 【UOJ#394】[NOI2018] 冒泡排序
题目链接 题意 求有多少个字典序严格大于给定排列 \(q_i\) 的排列满足其逆序对数(冒泡排序需要交换的次数)达到下限 \(\frac{1}{2}\sum_{i=1}^n |i-p_i|\) Sol ...
- luogu P4769 [NOI2018]冒泡排序 结论 树状数组 卡特兰数
LINK:冒泡排序 神题. 可以想到爆搜 期望得分5~10分. 打成这个样子心态不得爆炸? 仔细分析 一个不合法序列还有什么标志. 容易想到某个数字离自己位置相反的方向多走了一步. 考虑单独对每个数字 ...
- Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学
题目传送门 传送点 题目大意 给定$n$个标号依次为$1, 2, \cdots, n$的点,其中一些点被染成一些颜色,剩下的点没有染色.你需要添加一些有向边并将剩下的点染色,满足有向边从编号小的一端指 ...
- BZOJ2339 HNOI2011卡农(动态规划+组合数学)
考虑有序选择各子集,最后除以m!即可.设f[i]为选i个子集的合法方案数. 对f[i]考虑容斥,先只满足所有元素出现次数为偶数.确定前i-1个子集后第i个子集是确定的,那么方案数为A(2n-1,i-1 ...
随机推荐
- ASP.NET Core 中 HttpContext 详解与使用 | Microsoft.AspNetCore.Http 详解
笔者没有学 ASP.NET,直接学 ASP.NET Core ,学完 ASP.NET Core MVC 基础后,开始学习 ASP.NET Core 的运行原理.发现应用程序有一个非常主要的 “传导体” ...
- 【H5】dropload (移动端下拉刷新,上拉加载)
插件概要地址:http://ximan.github.io/dropload/ 一般下载其中的demo2对照修改即可使用. 小吐槽.我在项目中用的时候,有个后端说ajax麻烦但是还是要做体现他很热爱工 ...
- 大数据入门第二十二天——spark(二)RDD算子(1)
一.RDD概述 1.什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的 ...
- 20155334 《网络攻防》Exp4 恶意代码分析
<网络攻防>Exp4 恶意代码分析 一.实验问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些,用什么方法来监 ...
- jq 在字符串中,去掉指定的元素
例: var arr= ["4.5岁", "3.5岁", "5.5岁", "5岁", "4岁"] v ...
- 初识TPOT:一个基于Python的自动化机器学习开发工具
1. TPOT介绍 一般来讲,创建一个机器学习模型需要经历以下几步: 数据预处理 特征工程 模型选择 超参数调整 模型保存 本文介绍一个基于遗传算法的快速模型选择及调参的方法,TPOT:一种基于Pyt ...
- CS190.1x-ML_lab1_review_student
这是CS190.1x第一次作业,主要教你如何使用numpy.numpy可以说是python科学计算的基础包了,用途非常广泛.相关ipynb文件见我github. 这次作业主要分成5个部分,分别是:数学 ...
- python 算法面试题
1.题目是:有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法. def StringSort(data): startIndex=0 endIndex=0 count ...
- C# 基于泛型的自定义线性节点链表集合示例
本例子实现了如何自定义线性节点集合,具体代码如下: using System; using System.Collections; using System.Collections.Generic; ...
- TICTOC: Header Only C++ Timer
感觉最近的更新频率略高啊-哈哈- 这次的带来的是一个十分简单便利的C++计时库. 项目地址:https://github.com/miaoerduo/tictoc 欢迎Start和提MR. 项目中有详 ...