打表可以发现相当于不存在长度>=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冒泡排序(动态规划+组合数学)的更多相关文章

  1. BZOJ_5416_[Noi2018]冒泡排序_DP+组合数+树状数组

    BZOJ_5416_[Noi2018]冒泡排序_DP+组合数+树状数组 Description www.lydsy.com/JudgeOnline/upload/noi2018day1.pdf 好题. ...

  2. 【洛谷4769】[NOI2018] 冒泡排序(动态规划_组合数学)

    题目: 洛谷 4769 博客页面左下角的嘴嘴瓜封神之战中的题目 分析: 一个排列交换次数为 \(\frac{1}{2}\sum_{i=1}^{n}|i-p_i|\) 的充要条件是这个排列不存在长度为 ...

  3. [NOI2018]冒泡排序

    https://www.zybuluo.com/ysner/note/1261482 题面 戳我 \(8pts\ n\leq9\) \(44pts\ n\leq18\) \(ex12pts\ q_i= ...

  4. 【NOI 2018】冒泡排序(组合数学)

    题意大概是给定一个长度为$n$的排列$p$,求有多少长度为$n$的排列满足冒泡排序的交换次数为$\frac{1}{2} \sum\limits_{i = 1}^{n}|i - p_{i}|$. 可以发 ...

  5. [POJ1664] 放苹果 (动态规划,组合数学)

    题目描述 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分发(5,1,1和1,1,5是同一种方法) 输入输出格式 输入格式: 第一行是测试数据的数目t(0 <= ...

  6. 【UOJ#394】[NOI2018] 冒泡排序

    题目链接 题意 求有多少个字典序严格大于给定排列 \(q_i\) 的排列满足其逆序对数(冒泡排序需要交换的次数)达到下限 \(\frac{1}{2}\sum_{i=1}^n |i-p_i|\) Sol ...

  7. luogu P4769 [NOI2018]冒泡排序 结论 树状数组 卡特兰数

    LINK:冒泡排序 神题. 可以想到爆搜 期望得分5~10分. 打成这个样子心态不得爆炸? 仔细分析 一个不合法序列还有什么标志. 容易想到某个数字离自己位置相反的方向多走了一步. 考虑单独对每个数字 ...

  8. Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学

    题目传送门 传送点 题目大意 给定$n$个标号依次为$1, 2, \cdots, n$的点,其中一些点被染成一些颜色,剩下的点没有染色.你需要添加一些有向边并将剩下的点染色,满足有向边从编号小的一端指 ...

  9. BZOJ2339 HNOI2011卡农(动态规划+组合数学)

    考虑有序选择各子集,最后除以m!即可.设f[i]为选i个子集的合法方案数. 对f[i]考虑容斥,先只满足所有元素出现次数为偶数.确定前i-1个子集后第i个子集是确定的,那么方案数为A(2n-1,i-1 ...

随机推荐

  1. Android 导入工程文件引用包出错

    解决办法:将工程文件夹和引用文件夹需在同一目录下,问题解决.

  2. 使用navicat连接mysql时报错:2059 - authentication plugin 'caching_sha2_password'

    首先从本地登录mysql数据库,进入mysql控制台,输入如下命令: ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_passwo ...

  3. WPF 嵌入winform 控件

    引入 WindowsFormsIntegration.dll   和   System.Windows.Forms.dll <Window x:Class="wgscd.Window1 ...

  4. 20155321 《网络攻防》 Exp4 恶意代码分析

    20155321 <网络攻防> Exp4 恶意代码分析 计划任务监控 在C盘根目录下建立一个netstatlog.bat文件(先把后缀设为txt,保存好内容后记得把后缀改为bat),内容如 ...

  5. mfc 基类与子类

    基类(父类) 派生类(子类) 一.基类(父类) 基类(又称为父类,基类与派生类是相对的关系! 通过继承机制,可以利用已有的数据类型来定义新的数据类型.所定义的新的数据类型不仅拥有新定义的成员,而且还同 ...

  6. Java中的Calendar日历用法详解

    第一部分 Calendar介绍 public abstract class Calendar implements Serializable, Cloneable, Comparable<Cal ...

  7. chrome下的Grunt插件断点调试——基于node-inspector

    之前调试grunt插件时,都是通过人肉打log来调试.不仅效率低,而且会产生一堆无用的代码.于是简单google了下node断点调试的方法,总结了下. 借助node-inspector,我们可以通过C ...

  8. HTML 图像实例

    61.插入图像本例演示如何在网页中显示图像.图像标签(<img>)和源属性(Src)在 HTML 中,图像由 <img> 标签定义. <img> 是空标签,意思是说 ...

  9. Centos 7 安装mysql5.7.24二进制 版本

    Mysql 二进制安装方法 下载mysql https://dev.mysql.com/downloads/mysql/ 1.解压包 tar xf mysql-5.7.24-linux-glibc2. ...

  10. UE4官方行为树快速入门文档解析和修改

    近学习了UE4官方文档的行为树快速入门指南,发现里面的部分逻辑稍稍有点混乱和重叠,于是加入了自己的想法,修改了部分行为树逻辑,优化了其AI寻路能力. 初始的基本操作和资源创建同官方文档一样:1个Fol ...