ARC115 E

AtCoder

Problem Statement

Given is a sequence of \(N\) integers \(A_1\),\(A_2\),...,\(A_N\). Print the number, modulo \(998244353\), of sequence of \(N\) integers \(X_1\),\(X_2\),...,\(X_N\) satisfying all of the following conditions:

\(1 \leq X_i \leq A_i\)

  • \(X_i \not = X_{i+1} (1 \leq i \leq N-1)\)

Constraints

  • \(2 \leq N \leq 5 * {10}^5\)
  • \(1 \leq A_i \leq {10}^9\)

Input

Input is given from Standard Input in the following format:

\[N \\
A_1 A_2 ... A_N
\]

Output

Print the answer.

解法

题意说n个位置,每个位置上面的数字不能大于Ai,问每对相邻的数都不相同的序列数有多少个。这种问题一看就是容斥,用所有的减去不符合的。不符合的分为至少某1个位置不符合,至少某2个位置不符合……这样就可以用dp去做了。

dp[i][j]代表前i个元素分为j段的方案数,使得每段内的所有元素都相等。那么答案其实就是dp[n][n]-dp[n][n-1]+dp[n][n-2]...。这个转移方程是显然的:

\[dp[i][j] = \sum_{k \leq i-1} dp[k][j-1] * \min_{k+1 \leq l \leq i} A_k
\]

但是这个转移怎么看都要\(O(N^2)\),不过好在最终的容斥式子系数只与j的奇偶性有关,于是只考虑奇偶性转移:

\[dp[i][1] = \sum_{k \leq i-1} dp[k][0] * \min_{k+1 \leq l \leq i} A_k \\
dp[i][0] = \sum_{k \leq i-1} dp[k][1] * \min_{k+1 \leq l \leq i} A_k
\]

现在就是怎么去做这个转移的问题了。考虑到某个\(A_i\)的时候,\(A_i\)作为新的一段的转移,\(A_i\)是新的一段中的最小值:

[A1 , ... Aj] [Aj+1 ... Ai ... Ak]

这里\([A_{j+1} ... A_i ... A_k]\)是新添加上去的一段,可以发现\(l(i) \leq j \lt i\),\(i \leq k \leq r(i)\),其中\(l(i)\)是\(A_i\)左边第一个小于等于\(A_i\)的下标,\(r(i)\)是\(A_i\)右边第一个小于\(A_i\)的下标。这里用了不同的符号是规定同样大的数字,前面的更小,防止重复更新同一段。这么规定也不会漏掉,因为每一个新增的段一定有一个\(A_i\)会被我们遍历到。\(l(i)\)和\(r(i)\)可以通过单调栈轻松计算,这里不赘述。

这样的话,如果我们维护了当前元素左边所有dp值的前缀和,那么我们就可以快速获得所有满足条件的\(j\)的dp和,然后更新到这一段的末尾可能的取值,即\(k\)的范围:

rangeAdd(i+1, r[i], 0, preSum(l[i], i-1, 1) * A[i]);
rangeAdd(i+1, r[i], 1, preSum(l[i], i-1, 0) * A[i]);

这里的preSum(l, r, p)是\(\sum_{l \leq i \leq r} dp[i][p]\),rangeAdd可以通过数据结构维护,这里我们采用数组这种快速的数组结构来维护它:

rangeAdd(l, r, p, v) => diff[l][p] += v, diff[r+1][p] -= v;

这样这道题就做完了,以下是AC代码:

#pragma GCC optimize ("Ofast,unroll-loops")
#pragma GCC optimize("no-stack-protector,fast-math") #include <bits/stdc++.h> using namespace std; constexpr int N = 5e5+7;
constexpr int M = 998244353; #define fastio ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define int long long
#define pii pair<int, int>
#define fi first
#define se second
#define SZ(x) ((int)(x.size())) #ifdef int
#define INF 0x3f3f3f3f3f3f3f3f
#define INF2 (int)(0xcfcfcfcfcfcfcfcf)
#else
#define INF 0x3f3f3f3f
#define INF2 0xcfcfcfcf
#endif signed main() {
fastio
int n;
cin >> n;
vector<int> a(n+1, 0);
for (int i = 1; i <= n; i++) cin >> a[i];
auto add = [&](int& x, int y) {
x = (x % M + M + y % M) % M;
};
vector<int> l(n+1, 0), r(n+1, n+1);
vector<int> st;
for (int i = 1; i <= n; i++) {
while (!st.empty() and a[st.back()] > a[i])
st.pop_back();
l[i] = st.empty() ? 0 : st.back();
st.emplace_back(i);
}
st.clear();
for (int i = n; i >= 1; i--) {
while (!st.empty() and a[st.back()] >= a[i])
st.pop_back();
r[i] = st.empty() ? n+1 : st.back();
st.emplace_back(i);
}
st.clear(); vector<array<int, 2>> dp(n+1, {0, 0});
vector<array<int, 2>> sum(n+1, {0, 0});
vector<array<int, 2>> diff(n+2, {0, 0});
dp[0][0] = 1;
sum[0][0] = dp[0][0];
auto rangeAdd = [&](int l, int r, int parity, int v) {
add(diff[l][parity], v);
add(diff[r+1][parity], -v);
};
auto preSum = [&](int l, int r, int parity) {
return (sum[r][parity] - (l ? sum[l-1][parity] : 0ll) + M) % M;
};
for (int i = 1; i <= n; i++) {
int ll = l[i], lr = i-1;
int rl = i, rr = r[i]-1; add(diff[i][0], diff[i-1][0]);
add(diff[i][1], diff[i-1][1]); if (ll <= lr and rl <= rr) {
rangeAdd(rl, rr, 0, preSum(ll, lr, 1) * a[i]);
rangeAdd(rl, rr, 1, preSum(ll, lr, 0) * a[i]);
} add(dp[i][0], diff[i][0]);
add(dp[i][1], diff[i][1]); add(sum[i][0], sum[i-1][0]);
add(sum[i][1], sum[i-1][1]);
add(sum[i][0], dp[i][0]);
add(sum[i][1], dp[i][1]);
} cout << (dp[n][n&1] - dp[n][1^(n&1)] + M)%M << "\n";
return 0;
}

容斥+dp (一)的更多相关文章

  1. HDU 5794 A Simple Chess (容斥+DP+Lucas)

    A Simple Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 Description There is a n×m board ...

  2. [CF1086E]Beautiful Matrix(容斥+DP+树状数组)

    给一个n*n的矩阵,保证:(1)每行都是一个排列 (2)每行每个位置和上一行对应位置不同.求这个矩阵在所有合法矩阵中字典序排第几.考虑类似数位DP的做法,枚举第几行开始不卡限制,那么显然之前的行都和题 ...

  3. 【BZOJ3622】已经没有什么好害怕的了 容斥+DP

    [BZOJ3622]已经没有什么好害怕的了 Description Input Output Sample Input 4 2 5 35 15 45 40 20 10 30 Sample Output ...

  4. $bzoj2560$ 串珠子 容斥+$dp$

    正解:容斥+$dp$ 解题报告: 传送门$QwQ$ $umm$虽然题目蛮简练的了但还是有点难理解,,,我再抽象一点儿,就说有$n$个点,点$i$和点$j$之间有$a_{i,j}$条无向边可以连,问有多 ...

  5. 【XSY3156】简单计数II 容斥 DP

    题目大意 定义一个序列的权值为:把所有相邻的相同的数合并为一个集合后,所有集合的大小的乘积. 特别的,第一个数和最后一个数是相邻的. 现在你有 \(n\) 种数,第 \(i\) 种有 \(c_i\) ...

  6. bzoj3782上学路线(Lucas+CRT+容斥DP+组合计数)

    传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3782 有部分分的传送门:https://www.luogu.org/problemnew/ ...

  7. AGC 005D.~K Perm Counting(容斥 DP 二分图)

    题目链接 \(Description\) 给定\(n,k\),求 满足对于所有\(i\),\(|a_i-i|\neq k\)的排列的个数. \(2\leq n\leq 2000,\quad 1\leq ...

  8. ARC 101E.Ribbons on Tree(容斥 DP 树形背包)

    题目链接 \(Description\) 给定一棵\(n\)个点的树.将这\(n\)个点两两配对,并对每一对点的最短路径染色.求有多少种配对方案使得所有边都至少被染色一次. \(n\leq5000\) ...

  9. 【做题】51NOD1518 稳定多米诺覆盖——容斥&dp

    题意:求有多少种方案,用多米诺骨牌覆盖一个\(n\times m\)的棋盘,满足任意一对相邻行和列都至少有一个骨牌横跨.对\(10^9+7\)取模. \(n,m \leq 16\) 首先,这个问题的约 ...

  10. BZOJ 4361 isn 容斥+dp+树状数组

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4361 题意概述: 给出一个长度为N的序列A(A1,A2...AN).如果序列A不是非降的 ...

随机推荐

  1. Android的so库注入

    作者:Fly2015 Android平台的so库的注入是有Linux平台的进程注入移植来的.由于Android系统的底层实现是基于Linux系统的源码修改而来,因此很多Linux下的应用可以移植到An ...

  2. POJ3160强连通+spfa最长路(不错)

    题意:       给你一个有向图,每个点上有一个权值,可正可负,然后给你一些链接关系,让你找到一个起点,从起点开始走,走过的边可以在走,但是拿过权值的点就不能再拿了,问最多能拿到多少权值? 思路: ...

  3. Windows核心编程 第十五章 在应用程序中使用虚拟内存

    第1 5章 在应用程序中使用虚拟内存 Wi n d o w s提供了3种进行内存管理的方法,它们是: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常 ...

  4. 解决客户端Redis中文乱码问题

    启动客户端的时候添加 --raw 选项即可 wangyulong@code-local:~$ redis-cli 127.0.0.1:6379> set key1 '上海' OK 127.0.0 ...

  5. C++ primer plus读书笔记——第10章 对象和类

    第10章 对象和类 1. 基本类型完成了三项工作: 决定数据对象需要的内存数量: 决定如何解释内存中的位: 决定可使用数据对象执行的操作或方法. 2. 不必在类声明中使用关键字private,因为这是 ...

  6. 通过CRM系统实现工作流程自动化

    灵活运用CRM系统所拥有的自动化功能模块,是公司在快速发展和降低成本的关键保障.不管您的公司规模的大小,您企业的工作流程都必须遵照相同的流程反复操作.这种反复的工作是一个效率黑洞,长久以往会导致人力资 ...

  7. PostgreSQL条件表达式

      条件表达式在日常工作中很多场景都会用到,比如某个字段为空,取另外一个字段:某个值大于多少,取什么字段,小于多少取什么字段等等.那么下面来简单的学习下PostgreSQL有那些条件表达式. 1.CA ...

  8. Cookie&Session-授课

    1 会话技术 1.1 会话管理概述 1.1.1 什么是会话 会话:浏览器和服务器之间的多次请求和响应 为了实现一些功能,浏览器和服务器之间可能会产生多次的请求和响应,从浏览器访问服务器开始,到访问服务 ...

  9. 微服务&#183;API文档

    阅文时长 | 3.92分钟 字数统计 | 2754.05字符 主要内容 | 1.什么是API文档 2.API文档的使用 3.声明与参考资料 『微服务·API文档』 编写人 | SCscHero 编写时 ...

  10. (原创)高DPI适配经验系列:(四)高DPI适配示例

    一.前言 光说不练假把式. 原理说再多,也不如一个例子直观明了.所以本篇文章就来通过一个例子演示一下高DPI适配的流程. 相信看完的你,一定会有所收获! 本文地址:https://www.cnblog ...