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. 一份释放root文件的脚本文件

    #!/system/bin/sh MYDIR=$3 ARGS=$4 SU=$MYDIR/au SUPOLICY=$MYDIR/supolicy BUSYBOX=$MYDIR/busybox TOOLB ...

  2. hdu 5063 不错的小想法题(逆向处理操作)

    题意:       刚开始的时候给你一个序列,长度为n,分别为a[1]=1,a[2]=2,a[3]=3,a[4]=4...a[n]=n,然后有4种操作如下: Type1: O 1 call fun1( ...

  3. hdu5033 最大仰望角

    题意:       给你n个楼房排成一条直线,楼房可以看成是宽度为1的线段,然后给你m组询问,每组询问给你一个坐标,输出在当前坐标仰望天空的可视角度. 思路:       n比较大,O(n*m)肯定跪 ...

  4. POJ 2135 简单费用流

    题意:       题意是一个人他要从牧场1走到牧场n然后在走回来,每条路径只走一次,问全程的最短路径是多少. 思路:        这个题目挺简单的吧,首先要保证每条边只能走一次,然后还要要求费用最 ...

  5. 详解 WebRTC 传输安全机制:一文读懂 DTLS 协议

    作者|进学 审校|泰一 DTLS (Datagram Transport Layer Security) 基于 UDP 场景下数据包可能丢失或重新排序的现实情况下,为 UDP 定制和改进的 TLS 协 ...

  6. 视频格式mkv、mp4、avi、flv、mov、wmv、webm特点和区别

    mkv是一种多媒体封装格式,这个封装格式可把多种不同编码的影像及 16 条或以上不同格式的音频和语言不同的字幕封装到一个 Matroska Media 档内. 它也是其中一种开放原始码的多媒体封装格式 ...

  7. 使用constexpr时遇到的小坑

    最近在使用constexpr的时候无意中踩了个小坑. 下面给个小示例: #include <iostream> constexpr int n = 10; constexpr char * ...

  8. 改善c++程序的150个建议(读后总结)-------19-26

    19. 明白在c++中如何使用c c++可以兼容c的绝大部分代码,但是还是有一部分不能兼容. c语言的编译器在调用函数时会把函数翻译成 : "_函数名",例如: int nasa( ...

  9. CRM是什么意思,有哪些作用?

    我们总会听到一些人提到CRM或CRM系统,但是通常不知道它的含义,所以今天小Z就来详细介绍一下CRM. GartnerGroup1993年首次提出了这一概念:所谓的客户关系管理就是为企业提供一个全面的 ...

  10. 在?开源社区版的 AirTag 请收下——GitHub 热点速览 v.21.21

    作者:HelloGitHub-小鱼干 在比特币跌到怀疑人生的时候,看着"出血不止"的荷包,是时候来"薅"一波羊毛了.openhaystack 能让你免去购买 A ...