AtCoder ARC 115 E - LEQ and NEQ (延迟标记线段树 or 笛卡尔积 + DP维护)
问题链接:Here
长度为 \(N\) 的数列 \(A_1,…,A_N\) 。回答满足以下条件的长度 \(N\) 的数列 \(X_1,…,X_N\) 的个数除以 \(998244353\) 的余数。
- \(1\le X_i \le A_i\)
- \(X_i \not = X_{i + 1}\)
\(2\le N \le 5e5,1\le A_i \le 1e9\)
因为 $X_i \not = X_{i + 1} $ 的条件比较难处理,所以用容斥定理来做更好点
如果有 \(K\) 个相邻的相等,那么容斥系数为 \((-1)^k\) 。
那我们把 \(n\) 分为若干连续相同段,然后每一段容斥系数分开算,这样就是一个 dp 的转移式子了。
\]
这个 \(min\{A_k\}\) 每次加入一个新的时候会影响一个后缀,用单调栈找到这个后缀,然后把 \(f_i\) 丢进线段树里。
而那个容斥系数就是每次整个线段树乘上一个 (-1),这个丢到外面处理就好了
- \(\mathcal{O}(N\ log\ N)\)
using ll = long long;
using namespace std;
const ll N = 5e5 + 10, M = N << 2, P = 998244353;
ll n, a[N], q[N], f[N];
ll w[M], lazy[M], v[M];
void Downdata(ll x) {
if (!lazy[x])return;
w[x * 2] = v[x * 2] * lazy[x] % P;
w[x * 2 + 1] = v[x * 2 + 1] * lazy[x] % P;
lazy[x * 2] = lazy[x * 2 + 1] = lazy[x];
return;
}
void Change(ll x, ll L, ll R, ll l, ll r, ll c) {
if (L == l && R == r) {lazy[x] = c; w[x] = v[x] * c % P; return;}
ll mid = (L + R) >> 1; Downdata(x);
if (r <= mid)Change(x * 2, L, mid, l, r, c);
else if (l > mid)Change(x * 2 + 1, mid + 1, R, l, r, c);
else Change(x * 2, L, mid, l, mid, c), Change(x * 2 + 1, mid + 1, R, mid + 1, r, c);
w[x] = (w[x * 2] + w[x * 2 + 1]) % P; v[x] = (v[x * 2] + v[x * 2 + 1]) % P; return;
}
void Insert(ll x, ll L, ll R, ll pos, ll c) {
if (L == R) {v[x] = c; w[x] = c * lazy[x] % P; return;}
ll mid = (L + R) >> 1; Downdata(x);
if (pos <= mid)Insert(x * 2, L, mid, pos, c);
else Insert(x * 2 + 1, mid + 1, R, pos, c);
w[x] = (w[x * 2] + w[x * 2 + 1]) % P; v[x] = (v[x * 2] + v[x * 2 + 1]) % P; return;
}
signed main() {
scanf("%lld", &n);
ll top = 1; Insert(1, 1, n, 1, P - 1);
for (ll i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
while (top > 0 && a[i] < a[q[top]])top--;
Change(1, 1, n, q[top] + 1, i, a[i]); q[++top] = i;
f[i] = (i & 1) ? (P - w[1]) : w[1];
if (i != n)Insert(1, 1, n, i + 1, P - w[1]);
}
printf("%lld\n", f[n]);
return 0;
}
但是这道题是可以线性实现的,题目这个一个点可以控制一段区间的性质,可以考虑用 笛卡尔树 维护,维护一个栈、栈中存储 \(A_i\) 的下标和控制的权值两样东西,然后就可以根据奇偶性计算即可
- \(\mathcal{O}(N)\)
using ll = long long;
// modint
template<int MOD> struct Fp {
ll val;
constexpr Fp(ll v = 0) noexcept : val(v % MOD) {
if (val < 0) val += MOD;
}
constexpr int getmod() const { return MOD; }
constexpr Fp operator - () const noexcept {
return val ? MOD - val : 0;
}
constexpr Fp operator + (const Fp &r) const noexcept { return Fp(*this) += r; }
constexpr Fp operator - (const Fp &r) const noexcept { return Fp(*this) -= r; }
constexpr Fp operator * (const Fp &r) const noexcept { return Fp(*this) *= r; }
constexpr Fp operator / (const Fp &r) const noexcept { return Fp(*this) /= r; }
constexpr Fp &operator += (const Fp &r) noexcept {
val += r.val;
if (val >= MOD) val -= MOD;
return *this;
}
constexpr Fp &operator -= (const Fp &r) noexcept {
val -= r.val;
if (val < 0) val += MOD;
return *this;
}
constexpr Fp &operator *= (const Fp &r) noexcept {
val = val * r.val % MOD;
return *this;
}
constexpr Fp &operator /= (const Fp &r) noexcept {
ll a = r.val, b = MOD, u = 1, v = 0;
while (b) {
ll t = a / b;
a -= t * b, swap(a, b);
u -= t * v, swap(u, v);
}
val = val * u % MOD;
if (val < 0) val += MOD;
return *this;
}
constexpr bool operator < (const Fp &r) const noexcept {
return this->val < r.val;
}
constexpr bool operator == (const Fp &r) const noexcept {
return this->val == r.val;
}
constexpr bool operator != (const Fp &r) const noexcept {
return this->val != r.val;
}
friend constexpr istream &operator >> (istream &is, Fp<MOD> &x) noexcept {
is >> x.val;
x.val %= MOD;
if (x.val < 0) x.val += MOD;
return is;
}
friend constexpr ostream &operator << (ostream &os, const Fp<MOD> &x) noexcept {
return os << x.val;
}
friend constexpr Fp<MOD> modpow(const Fp<MOD> &r, ll n) noexcept {
if (n == 0) return 1;
if (n < 0) return modpow(modinv(r), -n);
auto t = modpow(r, n / 2);
t = t * t;
if (n & 1) t = t * r;
return t;
}
friend constexpr Fp<MOD> modinv(const Fp<MOD> &r) noexcept {
ll a = r.val, b = MOD, u = 1, v = 0;
while (b) {
ll t = a / b;
a -= t * b, swap(a, b);
u -= t * v, swap(u, v);
}
return Fp<MOD>(u);
}
};
const int MOD = 998244353;
using mint = Fp<MOD>;
using pll = pair<ll, ll>;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
stack<pll> st;
st.push({0, 0});
vector<mint> dp(n + 1, 0), sdp(n + 2, 0);
dp[0] = 1, sdp[1] = 1;
for (int i = 1; i <= n; ++i) {
ll t = a[i - 1];
while (!st.empty() && st.top().first >= t) st.pop();
ll num = st.top().second;
st.push({t, i});
if (num > 0) dp[i] += dp[num];
dp[i] -= (sdp[i] - sdp[num]) * t;
sdp[i + 1] = sdp[i] + dp[i];
}
mint ans = dp[n];
if (n & 1) ans = -ans;
cout << ans;
}
看了一下在推特上这道题的讨论发现线段树写法上还可以在坐标压缩一下,思路来源于 @opt_cp
AtCoder ARC 115 E - LEQ and NEQ (延迟标记线段树 or 笛卡尔积 + DP维护)的更多相关文章
- AtCoder Regular Contest 063 F : Snuke’s Coloring 2 (线段树 + 单调栈)
题意 小 \(\mathrm{C}\) 很喜欢二维染色问题,这天他拿来了一个 \(w × h\) 的二维平面 , 初始时均为白色 . 然后他在上面设置了 \(n\) 个关键点 \((X_i , Y_i ...
- Petrozavodsk Winter-2018. AtCoder Contest. Problem I. ADD, DIV, MAX 吉司机线段树
题意:给你一个序列,需要支持以下操作:1:区间内的所有数加上某个值.2:区间内的所有数除以某个数(向下取整).3:询问某个区间内的最大值. 思路(从未见过的套路):维护区间最大值和区间最小值,执行2操 ...
- 【题解】 AtCoder ARC 076 F - Exhausted? (霍尔定理+线段树)
题面 题目大意: 给你\(m\)张椅子,排成一行,告诉你\(n\)个人,每个人可以坐的座位为\([1,l]\bigcup[r,m]\),为了让所有人坐下,问至少还要加多少张椅子. Solution: ...
- ARC115E-LEQ and NEQ【容斥,dp,线段树】
正题 题目链接:https://atcoder.jp/contests/arc115/tasks/arc115_d 题目大意 \(n\)个数字的序列\(x\),第\(x_i\in [1,A_i]\ca ...
- HDU5785 Interesting(Manacher + 延迟标记)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5785 Description Alice get a string S. She think ...
- 数据结构--线段树--lazy延迟操作
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 53749 ...
- FZU 2171(线段树的延迟标记)
题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...
- [HDOJ4578]Transformation(线段树,多延迟标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4578 四种操作:查询.加法.乘法.改数.应该是需要维护三个lazy标记,然后就是套路了.查询是区间内所 ...
- 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)
欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others) Memor ...
- zoj 1610 Count the Colors(线段树延迟更新)
所谓的懒操作模板题. 学好acm,英语很重要.做题的时候看不明白题目的意思,我还拉着队友一块儿帮忙分析题意.最后确定了是线段树延迟更新果题.我就欣欣然上手敲了出来. 然后是漫长的段错误.... 第一次 ...
随机推荐
- Vue01-简介与入门
Vue 01. 简介 1.1 前端三大框架 目前前端最流行的三大框架: Vue React angular 1.2 Vue简介 Vue (读音 /vjuː/,类似于 view) ,也可以写成Vue.j ...
- javaweb项目搭建|前端项目【包含增删改查,mysql】二
首先,新建一个javaweb项目[前提已经下载tomcat,mysql,此实验idea版本为2022,其他版本可能位置不一样] File->New->Project 起一个项目名称(随便起 ...
- java 405_Http状态405-方法不允许
解决方法: 删除下列代码. super.doGet(req.resp); super.doPost(req.resp); 分析: 405错误一般指请求method not allowed 错误. 请求 ...
- 介绍一个我开源的项目:一键部署 VictoriaMetrics 群集
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 我实在是非常喜欢这个强大的 metrics 监控组件 Vi ...
- [ABC280F] Pay or Receive
Problem Statement There are $N$ towns numbered $1,\ldots,N$ and $M$ roads numbered $1,\ldots,M$. Roa ...
- Educational Codeforces Round 26 Problem C
C. Two Seals time limit per test 1 second memory limit per test 256 megabytes input standard input o ...
- ElasticSearch之cat plugins API
命令样例如下: curl -X GET "https://localhost:9200/_cat/plugins?v=true&pretty" --cacert $ES_H ...
- 斯坦福 UE4 C++ ActionRoguelike游戏实例教程 02.AI自定义任务和观察器中断
斯坦福课程 UE4 C++ ActionRoguelike游戏实例教程 0.绪论 概述 本文章对应课程第十一章 42节.这篇文章会进一步地为AI添加新功能,创建自定义任务,允许AI发射子弹,并且讲解观 ...
- Java异常处理之数字溢出问题
在进行 Java 开发时,经常会遇到数字溢出的问题.这个问题在很多程序中都非常常见,尤其是在进行数值计算的时候.Java 中提供了一种异常机制来处理这种情况,我们可以在代码中使用 try-catch ...
- 中秋国庆花式玩法,用低代码DIY假日大屏“Vlog”
本文分享自华为云社区 <[云享热点]中秋国庆花式玩法,用低代码DIY假日大屏"Vlog"(内附节日福利)>,作者:华为云社区精选. 中秋.国庆双节将至,你的八天小长 ...