LOJ 2719 「NOI2018」冒泡排序——模型转化
题目:https://loj.ac/problem/2719
首先要发现合法的充要条件是 | LDS | <=2 !
因为有没用的步数,说明一个元素先往左移、又往右移(不会先往右移再往左移,因为一旦往右移,说明它是前缀最大值,并且一直是),就说明它前面有一个比它大的、后面有一个比它小的,即有长度至少为 3 的 LDS 。
考虑 DP ,已填了前 i 个位置。注意到已经填过的最大的数最容易产生 LDS ,所以令 dp[ i ][ j ] 表示填了前 i 个位置、已填的最大数是 j 的方案数。
考虑第 i 个位置,如果填一个 < j 的数,只能填未填的最小数(这个发现很重要!),不然之后就会产生长度为 3 的 LDS 了;如果填一个 > j 的数,就没什么要注意的。
所以有 dp[ i ][ j ]*1 -> dp[ i+1 ][ k ] ( k>=j )
注意到系数全是 1 ,考虑用前缀和的思想来优化。就是 dp[ i ][ j ] 只向 dp[ i+1 ][ j ] 转移,然后 dp[ i ][ j ] 可以向 dp[ i ][ j+1 ] 转移。
如果 j = i ,考虑到没有 dp[ i+1 ][ j ] ,所以 dp[ i ][ j ] 向 dp[ i+1 ][ j+1 ] 转移即可。
每个状态画成二维格点,发现转移就是只能向右或向上、右下角一些位置不能走的 “从 ( 0 , 0 ) 走到 ( n , n ) ” 的方案数!可用卡特兰数。
那个斜着的边,把它改成横平竖直的即可。那么就是不能经过 y=x-2 这条直线。从 ( x1,y1 ) 走到 ( x2,y2 ) 的方案数就是 \( C_{x2-x1+y2-y1}^{x2-x1} - C_{x2-(y1+1)+y2-(x1-1)}^{x2-(y1+1)} \) 。
注意第0列是没有竖着的转移的。可以认为是从 ( 1 , 1 ) 走到 ( n , n ) 。
然后要保证字典序 > q 。考虑数位 DP 。
设当前做到第 i 位、之前都是贴着上界。设之前贴上界的已填数中最大值是 mx ,未填的最小值是 mn 。
第 i 位不贴上界,设填 k ,需要 k > q[ i ] ;还需要 k > mx ,因为若 k < mx ,又有 k > q[ i ] ,所以 mx , k , q[ i ] 会组成长度为 3 的 LDS 。
那么就是要 \( \sum\limits_{k>max(mx,q[i])} dp[i][k] \) ;这是一个后缀和,正好就是从 ( i , max( mx,q[ i ] )+1 ) 走到 ( n , n ) 的不经过 y=x-2 的方案数。
如果贴上界,需要满足 q[ i ] > mx || q[ i ] == mn ,不然会出现长度 >=3 的 LDS 。如果不满足的话,就没有从第 i 位往后贴上界的方案了,直接 break 掉。
注意预处理至 2*n 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
int Mx(int a,int b){return a>b?a:b;}
const int N=12e5+,mod=;//N=6e5*2!!!
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;}
int n,a[N],jc[N],jcn[N]; bool vis[N];
void init()
{
int lm=12e5;
jc[]=;for(int i=;i<=lm;i++)jc[i]=(ll)jc[i-]*i%mod;
jcn[lm]=pw(jc[lm],mod-);
for(int i=lm-;i>=;i--)jcn[i]=(ll)jcn[i+]*(i+)%mod;
}
int C(int n,int m)
{
if(n<||m<||n<m)return ;
return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;
}
int cal(int x,int y)
{ return upt(C(*n-x-y,n-x)-C(*n-x-y,n-y-));}
int main()
{
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
int T=rdn(); init();
while(T--)
{
n=rdn(); for(int i=;i<=n;i++)a[i]=rdn();
memset(vis,,sizeof vis); int mn=,mx=,ans=;
for(int i=;i<=n;i++)
{
ans=upt(ans+cal(i,Mx(a[i],mx)+));
if(a[i]<mx&&a[i]!=mn)break;
mx=Mx(mx,a[i]); vis[a[i]]=;
while(i<n&&vis[mn])mn++;
}
printf("%d\n",ans);
}
return ;
}
LOJ 2719 「NOI2018」冒泡排序——模型转化的更多相关文章
- Loj #2719. 「NOI2018」冒泡排序
Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...
- loj 2719 「NOI2018」冒泡排序 - 组合数学
题目传送门 传送门 题目大意 (相信大家都知道) 显然要考虑一个排列$p$合法的充要条件. 考虑这样一个构造$p$的过程.设排列$p^{-1}_{i}$满足$p_{p^{-1}_i} = i$. 初始 ...
- LOJ #2719. 「NOI2018」冒泡排序(组合数 + 树状数组)
题意 给你一个长为 \(n\) 的排列 \(p\) ,问你有多少个等长的排列满足 字典序比 \(p\) 大 : 它进行冒泡排序所需要交换的次数可以取到下界,也就是令第 \(i\) 个数为 \(a_i\ ...
- LOJ 3056 「HNOI2019」多边形——模型转化+树形DP
题目:https://loj.ac/problem/3056 只会写暴搜.用哈希记忆化之类的. #include<cstdio> #include<cstring> #incl ...
- LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)
题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...
- loj#2721. 「NOI2018」屠龙勇士
题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...
- 「NOI2018」冒泡排序
「NOI2018」冒泡排序 考虑冒泡排序中一个位置上的数向左移动的步数 \(Lstep\) 为左边比它大的数的个数,向右移动的步数 \(Rstep\) 为右边比它大的数的个数,如果 \(Lstep,R ...
- loj#2718. 「NOI2018」归程
题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...
- LOJ2719 「NOI2018」冒泡排序
「NOI2018」冒泡排序 题目描述 最近,小S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 1 到n 的排列的冒泡排序. 下面是对冒泡排序的算法描述. 输入:一个长度为n 的排列p[ ...
随机推荐
- 16/7/14-MySQL-修改mysql5.6以上版本root密码
版本更新,原来user里的password字段已经变更为authentication_string 版本更新 缘故,好多网上的教程都不适用了,甚至连官网的文档也不是能够顺利操作的. 如果 MySQL ...
- 安卓中java和js如何交互
1.安卓中java和js如何交互 在Android上怎样实现JAVA和JS交互呢?Android的webview是基于webkit内核的,webview中集成了js与java互调的接口函数,通过add ...
- 模拟赛T5 : domino ——深搜+剪枝+位运算优化
这道题涉及的知识点有点多... 所以还是比较有意思的. domino 描述 迈克生日那天收到一张 N*N 的表格(1 ≤ N ≤ 2000),每个格子里有一个非 负整数(整数范围 0~1000),迈克 ...
- 结合Pool进程池进程,实现进程之间的通讯,稍微复杂的运用
#进程池中的Queue """ 如果要用Pool创建进程,就需要multiprocessing.Manager()中的Queue() 而不是multiprocessing ...
- python装饰器(基础中的重点)
一.简单的装饰器 1.为什么要使用装饰器呢? 装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展 装饰器的本质:就是一个闭包函数 那么我们先来看一个简单的装饰器:实现计算每个函数的执 ...
- [Linux] 008 文件处理命令
1. 文件处理命令:touch 命令名称:touch 命令所在路径:/bin/touch 执行权限:所有用户 语法:touch [文件名] 功能描述:创建空文件 范例: 文件名不包含空格 touch ...
- tmux多终端工具
在Linux服务器上没有办法像在桌面系统一样开多个终端,所以有时后进行一些操作不是太方便,所以可以使用tmux工具,创建多个终端. 这里仅仅是简单的介绍一下如何创建多个终端和进行多个终端之间切换,tm ...
- 55-python基础-python3-字典-删除键值对-del语句
字典-键值对的彻底删除 对于字典中不再需要的信息,可使用del 语句将相应的键—值对彻底删除. 使用del 语句时,必须指定字典名和要删除的键. 注意 删除的键—值对永远消失了.
- 如何写一个简单的基于 Qt 框架的 HttpServer ?
httpserver.h #ifndef HTTPSERVER_H #define HTTPSERVER_H #include <QObject> #include <QtCore& ...
- P2944 [USACO09MAR]地震损失2Earthquake Damage 2(网络流)
P2944 [USACO09MAR]地震损失2Earthquake Damage 2 $P$个点,$C$条双向边.求最少删去几个点使$N$个给定的点与点$1$分开. 显然的最小割. 将点$i$套路地拆 ...