专栏文章

2025 超新星战队 B 队暑假集训模拟赛 day1

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mioe4iyb
此快照首次捕获于
2025/12/02 17:43
3 个月前
此快照最后确认于
2025/12/02 17:43
3 个月前
查看原文

A. LIS

题面

给一个数组 a1,a2,,ana_1, a_2, \dots, a_n,定义 f(L,R)f(L, R) 的值为:
  1. 设当前索引为 i:=Li := L,答案为 11
  2. 对于 i<jRi < j \leq R,选取最小的 jj,满足 aj>aia_j > a_i。如果找不到 jj,则结束程序。
  3. i:=ji := j,并将答案增加 11。然后跳转到步骤 2。
L=1nR=Lnf(L,R)\sum_{L=1}^{n} \sum_{R=L}^{n} f(L, R)

输入格式

第一行包含一个整数 TT,表示 TT 组测试数据。
对于每组测试数据:
第一行包含一个整数 nn
接下来一行包含 nn 个整数 a1,a2,,ana_1, a_2, \dots, a_n

输出格式

对于每组测试数据,输出一行包含一个整数,表示答案。

数据范围

对于所有数据,保证 1T,n,n4105,1ain1 \leq T,n,\sum n \leq 4 \cdot 10^5, 1 \leq a_i \leq n

思路

先固定 ll。套路地,设 #(i)\#(\ge i)r=lnf(l,r)i\sum_{r=l}^n \left|f(l, r) \ge i\right|,则有 r=lnf(l,r)=i=1n#(i)\sum_{r=l}^n f(l, r) = \sum_{i=1}^{n} \#(\ge i)
ngei\text{nge}_i 为满足 i<jnai<aji < j \leq n \land a_i < a_j 的最小的 jj,若不存在这样的 jj,则设 ngei=n+1\text{nge}_i = n + 1
r(i)=ni+1r(i) = n - i + 1。注意到 #(1)=rl\#(\ge 1) = r_l#(2)=r(ngel)\#(\ge 2) = r(\text{nge}_l),同理可得 #(3)=r(ngengel)\#(\ge 3) = r(\text{nge}_{\text{nge}_l})#(4)=r(ngengengel)\#(\ge 4) = r(\text{nge}_{\text{nge}_{\text{nge}_l}})……
u[n]u \in [n]。因为有 u<nge(u)u < \text{nge}(u),所以如果将 ungeuu \gets nge_u 视作 gg 的一条有向边,那么 gg 就是一张以 n+1n+1 为根的树。
sus_u 为所有点 vvr(v)r(v) 之和,满足 vvuun+1n+1 的简单路径上。容易在 Θ(n)\Theta(n) 时间计算出 ss 的和,即答案。

实现

CPP
#include <bits/stdc++.h>
using namespace std;

using ll = long long;

constexpr int N = 400000 + 1;

int a[N + 1], stk[N + 1], f[N + 1];

void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
	}
	a[n + 1] = 1 << 30;
	f[n + 1] = 0;
	int top = 1;
	stk[top] = n + 1;
	for (int i = n; i; --i) {
		while (top && a[stk[top]] <= a[i]) {
			--top;
		}
		f[i] = n - i + 1 + f[stk[top]];
		stk[++top] = i;
	}
	cout << accumulate(f + 1, f + n + 1, 0ll) << '\n';
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}
时空复杂度:均为 Θ(n)\Theta(n)

评论

0 条评论,欢迎与作者交流。

正在加载评论...