Increasing Subsequence
时间:2021-07-30
本文章向大家介绍Increasing Subsequence,主要包括Increasing Subsequence使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目大意
给一个排列,问有多少个极大上升子序列,极大是指这个序列不能是其他上升子序列的子序列。
题解
令\(f_i\)表示以\(i\)结尾的子序列个数,那么转移的话枚举前面比它小的位置,转移的话这两个位置之间不能有这两个值之间的数。
考虑分治算这个东西,我们分治\((l,mid)\)和\((mid+1,r)\)两个区间,计算两个区间之间的贡献,那么我们先去归并这两个序列,在归并的过程中,对于右边序列,我们维护一个位置单调上升的单调栈,左边维护单调下降的单调栈,这样,在右边序列,我们可以利用单调栈找到它前面比它小的最大的元素, 左边的单调栈维护的是合法转移的位置,最后再左边二分出比那个最大的元素大的位置,转移过来即可。
代码
#include<bits/stdc++.h>
#define N 200009
using namespace std;
typedef long long ll;
const int mod=998244353;
int a[N],n,b[N],c[N],pos[N];
int st[N],st1[N],dp[N],dp1[N];
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline void MOD(int &x){x=x>=mod?x-mod:x;}
inline void solve(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
solve(l,mid);
for(int i=l;i<=mid;++i){
b[i]=a[i];
}
for(int i=mid+1;i<=r;++i){
c[i]=a[i];
}
sort(b+l,b+mid+1);
sort(c+mid+1,c+r+1);
int s1=l,s2=mid+1;
int top1=0,top=0;
while(s1<=mid&&s2<=r){
if(b[s1]<c[s2]){
while(top1&&pos[st1[top1]]<pos[b[s1]])top1--;
st1[++top1]=b[s1];
MOD(dp1[top1]=dp1[top1-1]+dp[pos[b[s1]]]);
s1++;
}
else{
while(top&&pos[st[top]]>pos[c[s2]])top--;
int now=0;
if(top)now=st[top];
st[++top]=c[s2];
int x=max(0ll,upper_bound(st1+1,st1+top1+1,now)-st1-1);
MOD(dp[pos[c[s2]]]+=(dp1[top1]-dp1[x]+mod)%mod);
s2++;
}
}
while(s2<=r){
while(top&&pos[st[top]]>pos[c[s2]])top--;
int now=0;
if(top)now=st[top];
st[++top]=c[s2];
int x=max(0ll,upper_bound(st1+1,st1+top1+1,now)-st1-1);
MOD(dp[pos[c[s2]]]+=(dp1[top1]-dp1[x]+mod)%mod);
s2++;
}
solve(mid+1,r);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
n=rd();
for(int i=1;i<=n;++i)a[i]=rd(),pos[a[i]]=i;
int mx=1e9;
for(int i=1;i<=n;++i){
if(pos[i]<mx)dp[pos[i]]=1;
else dp[pos[i]]=0;
mx=min(mx,pos[i]);
}
solve(1,n);
int ans=0;
mx=0;
for(int i=n;i>=1;--i){
if(pos[i]>mx)MOD(ans+=dp[pos[i]]);
mx=max(mx,pos[i]);
}
printf("%lld\n",ans);
}
return 0;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/15081176.html
- Windows 7上IIS出现http 500错误
- [C#2] 2-匿名方法
- jquery 操作css 选择器
- 主页后台源码及释义
- [C#2] 3-局部类型、属性访问器保护级别、命名空间别名限定符
- (2013.09更新)最新W3School 离线完整版CHM 电子书下载
- [C#2] 1-泛型
- .NET4.0的可扩展缓存系统
- 让WordPress 在RSS 中Feed 截断文字输出
- [C#1] 11-接口
- jquery 标签中的属性操作
- 使用MongoDB存储访问者信息
- 解决WordPress 打开Feed页面“This page contains the following errors…”的问题
- jquery表单属性筛选元素
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法