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. Python中的可迭代Iterable和迭代器Iterator

    目录 Iterable可迭代对象 如何判断对象是否是可迭代对象Iterable Iterator迭代器 如何判断对象是否迭代器Iterator 将Iterable转换成Iterator Iterabl ...

  2. CVE-2017-11882:Microsoft office 公式编辑器 font name 字段栈溢出通杀漏洞调试分析

    \x01 漏洞简介 在 2017 年 11 月微软的例行系统补丁发布中,修复了一个 Office 远程代码执行漏洞(缓冲区溢出),编号为 CVE-2017-11882,又称为 "噩梦公式&q ...

  3. c# p/invoke 无法加载指定的dll 找不到指定的模块 解决方法

    写的程序本来开始好好的,不知道怎么突然就出现了以上这个问题,纠结了好久,网上找了各种方法,比如什么嵌入dll,在system32下面放入dll等等,均宣告失败 下面把我的解决方法写出来,以后只要是这个 ...

  4. 【maven】Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.3:site (default-site)

    问题描述 site一点击就报错,如下 Failed to execute goal org.apache.maven.plugins:maven-site-plugin:3.3:site (defau ...

  5. layui图片上传

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>up ...

  6. 多线程-4.wait() notify() notifyAll() 生产者消费者模型

    1.wait()方法 该方法继承于Object类.在调用obj.wait()方法后,当前线程会失去obj的锁.待其他线程调用obj.notify()或notifyAll()方法后进入锁等待池,争抢到锁 ...

  7. (转)解决c#自带的HttpClient(Http.GetFromJsonAsync Http.GetStringAsync等)返回中文乱码问题

    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var aa = await Http.GetByteArrayAsync ...

  8. Django 请求和响应 request return

    request.method 请求方法 request.get  get请求信息 request.post  post请求信息 request.path 请求路径 方法: requset.get_fu ...

  9. HUGO 创建属于自己的博客

    Hugo 拥有超快的速度,强大的内容管理和强大的模板语言,使其非常适合各种静态网站.可以轻松安装在macOS,Linux,Windows等平台上,在开发过程中使用LiveReload可即时渲染更改 一 ...

  10. CSS3边界图片

    目录 border-image border-image-slice border-image-width border-image-outset border-image-repeat border ...