题目链接

题目

题目描述

一天,小魂正和一个数列玩得不亦乐乎。

小魂的数列一共有n个元素,第i个数为Ai。

他发现,这个数列的一些子序列中的元素是严格递增的。

他想知道,这个数列一共有多少个长度为K的子序列是严格递增的。

请你帮帮他,答案对998244353取模。

对于100%的数据,1≤ n ≤ 500,000,2≤ K ≤ 10,1≤ Ai ≤ 109。

输入描述

第一行包含两个整数n,K,表示数列元素的个数和子序列的长度。

第二行包含n个整数,表示小魂的数列。

输出描述

一行一个整数,表示长度为K的严格递增子序列的个数对998244353取模的值。

示例1

输入

5 3
2 3 3 5 1

输出

2

说明

两个子序列分别是 2 3 3 5 1 和 2 3 3 5 1 。

题解

知识点:树状数组,枚举,线性dp。

仿照最长上升子序列的状态,设 \(f_{i,j}\) 为以第 \(i\) 个数结尾且长度为 \(j\) 的上升子序列个数,显然是 \(O(n^2k)\) 的。其中可以优化的步骤是,查找上一个比自己小的元素。对于最长上升子序列优化查找的步骤,通常有三种方法,我们依次考虑是否适合用于这道题的状态:

  1. 改变状态,设 \(f_i\) 为长度为 \(i\) 的上升子序列的最小结尾数字,其有单调递增的性质,因此每次新增数字,二分查找最后一个小于自己数字的位置即可。但是,这个显然不适合用来优化这道题的状态。
  2. 优化查找,用数据结构维护前缀权值最大值,即以数字作为下标维护每个数字结尾的最大长度。这个方法是可以考虑的,我们将维护最大长度改为各个长度的上升子序列个数即可。
  3. 排序+优化查找,将数字顺序改为从小到大输入,用数据结构维护前缀最大值,即在原本的区间上维护每个位置结尾的最大长度,输入顺序保证了每次询问的答案一定都是比自己小的数字构成的答案,都是可以接上的。这个方法同样也是可以考虑的,我们将维护最大长度改为各个长度的上升子序列个数即可。

第二种方法需要先离散化,我们这里使用的是第三种方法,先排序后优化查找,复杂度上是没有区别的。

需要注意的是,使用第三种方法从小到大枚举时,因为要求的是上升子序列,所以相等的数字不能直接更新到数据结构中,需要等到所有相等的数字都查询完,才能一并更新。第二种方法由于直接维护权值关系,大小可以直接确定,则没有这种情况。

时间复杂度 \(O(nk \log n)\)

空间复杂度 \(O(nk)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; const int P = 998244353; template<class T>
class Fenwick {
int n;
vector<T> node; public:
Fenwick(int _n = 0) { init(_n); } void init(int _n) {
n = _n;
node.assign(n + 1, T());
} void update(int x, T val) { for (int i = x;i <= n;i += i & -i) node[i] += val; } T query(int x) {
T ans = T();
for (int i = x;i;i -= i & -i) ans += node[i];
return ans;
}
}; int k;
struct T {
array<int, 17> f = {};
T &operator+=(const T &x) {
for (int i = 1;i <= k;i++) (f[i] += x.f[i]) %= P;
return *this;
}
}; pair<int, int> a[500007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n >> k;
for (int i = 1;i <= n;i++) {
int x;
cin >> x;
a[i] = { x,i };
}
sort(a + 1, a + n + 1, [&](auto a, auto b) {return a.first < b.first;}); int ans = 0;
Fenwick<T> fw(n);
vector<pair<int, array<int, 17>>> v;
for (int i = 1;i <= n;i++) {
if (a[i].first != a[i - 1].first) {
for (auto [id, f] : v) fw.update(id, { f });
v.clear();
}
auto res = fw.query(a[i].second).f;
for (int j = k;j >= 1;j--) res[j] = res[j - 1];
res[1] = 1;
(ans += res[k]) %= P;
v.push_back({ a[i].second,res });
}
cout << ans << '\n';
return 0;
}

NC54585 小魂和他的数列的更多相关文章

  1. 陕西师范大学第七届程序设计竞赛网络同步赛 J 黑猫的小老弟【数论/法拉数列/欧拉函数】

    链接:https://www.nowcoder.com/acm/contest/121/J来源:牛客网 题目描述 大家知道,黑猫有很多的迷弟迷妹,当然也有相亲相爱的基友,这其中就有一些二五仔是黑猫的小 ...

  2. 【BZOJ 1430】 1430: 小猴打架 (Prufer数列)

    1430: 小猴打架 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 625  Solved: 452 Description 一开始森林里面有N只互不相 ...

  3. java小程序 示例 菲薄垃圾数列

    package com.test; import java.util.Scanner; import org.junit.Test; import com.sun.xml.internal.ws.ap ...

  4. E - 小晴天老师系列——我有一个数列!

    E - 小晴天老师系列——我有一个数列! Time Limit: 20000/10000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/O ...

  5. [编程题] 小易喜欢的数列 dp

    https://www.nowcoder.com/question/next?pid=6291726&qid=112729&tid=12736753 [编程题] 小易喜欢的数列 时间限 ...

  6. acdream 小晴天老师系列——我有一个数列! (ST算法)

    小晴天老师系列——我有一个数列! Time Limit: 20000/10000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)S ...

  7. 小X归来 模拟赛1 解析

    Problem1 单峰 小X 归来后,首先对数列很感兴趣.他想起有1类特殊的数列叫单峰数列. 我们说一个数列 {ai} 是单峰的,当且仅当存在一个位置 k 使得 ai < ai+1(i < ...

  8. lly的数列询问(最小生成树 + 思维)

    lly的数列询问 Description 这个问题很简单,lly lly lly给你一些提示,让你试着确定长度为n n n的数列A [1] A [2] ... A [n]的值,但是他想尽一切办法为大家 ...

  9. 基本排序算法的Python实现

    本篇主要实现九(八)大排序算法,分别是冒泡排序,插入排序,选择排序,希尔排序,归并排序,快速排序,堆排序,计数排序.希望大家回顾知识的时候也能从我的这篇文章得到帮助. 为了防止误导读者,本文所有概念性 ...

  10. bzoj1005 [HNOI2008]明明的烦恼

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 3032  Solved: 1209 Description ...

随机推荐

  1. 在Vue的mixins(混入)里面调用Vuex(@/store/index.js)的函数

    第一步:在mixin.js里面引入 mapMutations 第二步:跟组件内调用一样,在methods里面写 "...mapMutations(['xxx'])",   然后LZ ...

  2. 关于tomcat部署web服务方式

    方式1.apache-tomcat-8.0.47\webapps文件夹下放war包会自动解压.文件夹名称就是访问路径 方式2.apache-tomcat-8.0.47\conf\Catalina\lo ...

  3. OSPF的收敛特性

  4. OS基础-四大基本特征

    现代计算机操作系统的四大基本特性(并发/共享/虚拟/异步) 1.并发性 1.1.并发与并行区别 并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令.并发需要硬件支持,如多流 ...

  5. NodeJs 版本管理

    nvm-windows 说明:nvm是Nodejs的版本管理器.在开发中项目可能需要低版本或者高版本的Nodejs运行环境,以此我们可以使用nvm来切换Nodejs的版本. 在安装NVM for Wi ...

  6. Java所用相关软件的大致安装流程

    JAVA下载流程 一.相关环境的安装与配置 1.JDK的下载 去官网搜索相应的java版本,并进行下载 官网链接:www.xfdown.com/soft/125774.html在该链接下,可以下载ja ...

  7. 带你深入Java Log框架,彻底搞懂Log4J、Log4J2、LogBack,SLF4J

    最近系统被扫出来还在使用老旧的log4j,需要升级到最新的log4j.但是在升级的发现,Java相关的日志处理库有log4j, log4j2,slf4j和logback,初一看确实有点头大,那么区别是 ...

  8. 工良出品:包教会,Hadoop、Hive 搭建部署简易教程

    目录 导读 Hadoop.Hive 是什么 运行环境 Java 环境 Mysql 下载 Hadoop.Hive 和 驱动 安装 Hadoop core-site.xml hdfs-site.xml m ...

  9. 如何单机部署多个 MySQL 8.0 实例 ?

    在服务器资源有限的情况下,可利用该方案快速搭建各类 mysql 架构方案.各 MySQL 实例共享一个 mysqld 主程序,但各实例数据目录是独立的,存放在不同的文件夹中:好了.废话不多说,直接上干 ...

  10. grub 命令使用

    命令列表 ubuntu 的 iso 盘内一般有 command.lst 这个文件,里面是 grub 支持的命令 加载字体 ( 方便中文显示 ) grub> loadfont $prefix/fo ...