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. Known Notation 39届亚洲赛牡丹江站K题

    题意:       题意,哎!说道题意就蛋疼啊,比赛的时候就愣是把这个题目读成数字可以随意组合,比如123 可以拆成1 23 ,12 3 ,1 2 3,结果显然,水题当神题,各种想不出来,然后就显然的 ...

  2. 声明:songzijian这个域名已经被抢注。大家别上了。不是我了。

    声明:songzijian这个域名已经被抢注.大家别上了.不是我了.

  3. 初入MongoDB

    初入MongoDB 业务需求,需要用到MongoDB.向来一直是mysql数据库的思想,一下转换为nosql还是很不适应.经过一个月的开发,写一下自己的感触.本文会对应mysql数据库进行说明. 数据 ...

  4. 【js】Leetcode每日一题-完成所有工作的最短时间

    [js]Leetcode每日一题-完成所有工作的最短时间 [题目描述] 给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间. 请你将这些工作分配给 k 位工人.所有工 ...

  5. 建立AD域,修改密码后不重启生效命令

    net user administrator /passwordreq:yes

  6. .NET 在信创常用软件适配清单之中?

    2020年8月份写了一篇文章<.NET Core也是国产化信息系统开发的重要选项>, 这又过去了大半年了,在信创领域发生了很大的变化,今天写这篇文章主要是想从信创常用软件适配清单 看一看. ...

  7. 26.Set

    1.Set集合 1.1Set集合概述和特点[应用] 可以去除重复 存取顺序不一致 没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取,删除Set集合里面的元素 1.2Set集合的使 ...

  8. 国内Ubuntu16.04下载地址<其他系统可返回最首项>

     ubuntu16.04下载地址: 中科大源       http://mirrors.ustc.edu.cn/ubuntu-releases/16.04/ 阿里云开源镜像站       http:/ ...

  9. 使用GitHub绑定域名免费创建自己的博客

    通过GitHub创建一个免费的.有上传网页功能的.可以绑定域名的个人博客,或者网站. 在这之前的必要条件: 1.有自己的域名,能添加CNAME或者A记录 2.注册好了GitHub账号 方法: 1.添加 ...

  10. Vim安装记录

    Vim安装记录 参考链接 安装命令 1. 安装依赖库 2. 下载最新vim源码 3. 删除旧版vim 4. 配置configure.编译.安装 5. 设置vim为默认编辑器 6. 必要的配置 Vim安 ...