首页 > 其他分享 >C2. Magnitude (Hard Version)

C2. Magnitude (Hard Version)

时间:2024-06-13 19:47:33浏览次数:12  
标签:geq Version int value leq Magnitude 操作 test C2

C2. Magnitude (Hard Version)

The two versions of the problem are different. You may want to read both versions. You can make hacks only if both versions are solved.

You are given an array $a$ of length $n$. Start with $c = 0$. Then, for each $i$ from $1$ to $n$ (in increasing order) do exactly one of the following:

  • Option $1$: set $c$ to $c + a_i$.
  • Option $2$: set $c$ to $|c + a_i|$, where $|x|$ is the absolute value of $x$.

Let the maximum final value of $c$ after the procedure described above be equal to $k$. Find the number of unique procedures that result in $c = k$. Two procedures are different if at any index $i$, one procedure chose option $1$ and another chose option $2$, even if the value of $c$ is equal for both procedures after that turn.

Since the answer may be large, output it modulo $998\,244\,353$.

Input

The first line contains a single integer $t$ ($1 \leq t \leq 10^4$) — the number of test cases.

The first line of each test case contains a single integer $n$ ($2 \leq n \leq 2 \cdot 10^5$).

The second line of each test case contains $n$ integers $a_1, a_2, \ldots, a_n$ ($-10^9 \leq a_i \leq 10^9$).

The sum of $n$ over all test cases does not exceed $3 \cdot 10^5$.

Output

For each test case, output a single integer — the number of unique procedures that result in $c = k$, modulo $998\,244\,353$.

Example

input

5
4
2 -5 3 -3
8
1 4 3 4 1 4 3 4
3
-1 -2 -3
4
-1000000000 1000000000 1000000000 1000000000
4
1 9 8 4

output

12
256
1
8
16

Note

In the first test case, it can be shown that our maximal final value of $c$ is $3$. There are $12$ ways to achieve this because in order to get $3$, we have to take absolute value at indices $2$ or $4$, or both, resulting in $3$ ways. For the other two indices, it doesn't change the value whether we take absolute value or not, so we have $2 \cdot 2 = 4$ ways for them. In total, we have $3 \cdot 4 = 12$ ways.

In the second test case, taking the absolute value will never change anything, so we can either take absolute value or not, for every index. This gives us $2^8 = 256$ possible ways.

 

解题思路

  先考虑动态规划,定义 $f(i,0/1)$ 表示对前 $i$ 个数操作的所有方案中的最大值 $/$ 最小值。直接暴力转移即可,即有:

$$
\begin{align*}
f(i,0) &= \max\left\{ f(i-1,0) + a_i, \, |f(i-1,0) + a_i|, \, f(i-1,1) + a_i, \, |f(i-1,1) + a_i| \right\} \\
f(i,1) &= \min\left\{ f(i-1,0) + a_i, \, |f(i-1,0) + a_i|, \, f(i-1,1) + a_i, \, |f(i-1,1) + a_i| \right\}
\end{align*}
$$

  之所以要考虑最小值,是因为 $|f(i-1,1) + a_i|$ 有可能会比 $f(i-1,0) + a_i$ 大。

  最后答案就是 $f(n,0)$。

  接下来考虑如何求方案数,定义 $g(i,0/1)$ 表示在前 $i$ 个数中取得 $f(i,0/1)$ 的方案数。从上面的状态转移方程可以知道,如果某个 $f(i-1,*)$ 可以转移到 $f(i,0/1)$,那么这个状态对应的 $g(i-1, *)$ 就可以转移到 $g(i,0/1)$,即

$$
\begin{cases}
g(i,j) \gets g(i-1,0), &\text{if} &f(i,0) = f(i-1,0) + a_i \\
g(i,j) \gets g(i-1,0), &\text{if} &f(i,0) = |f(i-1,0) + a_i| \\
g(i,j) \gets g(i-1,1), &\text{if} &f(i,1) = f(i-1,1) + a_i \\
g(i,j) \gets g(i-1,1), &\text{if} &f(i,1) = |f(i-1,1) + a_i| \\
\end{cases}
\quad j = 0,1
$$

  不过需要注意的是,如果 $f(i-1,0) = f(i-1,1)$,意味着这两种情况对应的操作方案是完全一样的,此时我们应该选择其中一种情况(最大值或最小值)转移到 $g(i,0/1)$,否则方案数就会有重复。

  最后答案就是 $g(n,0)$。

  AC 代码如下,时间复杂度为 $O(n)$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, mod = 998244353;

int a[N];
LL f[N][2], g[N][2];

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
    }
    g[0][0] = g[0][1] = 1;
    for (int i = 1; i <= n; i++) {
        f[i][0] = max({f[i - 1][0] + a[i], abs(f[i - 1][0] + a[i]), f[i - 1][1] + a[i], abs(f[i - 1][1] + a[i])});
        f[i][1] = min({f[i - 1][0] + a[i], abs(f[i - 1][0] + a[i]), f[i - 1][1] + a[i], abs(f[i - 1][1] + a[i])});
        for (int j = 0; j <= 1; j++) {
            g[i][j] = 0;
            if (f[i][j] == f[i - 1][0] + a[i]) g[i][j] = (g[i][j] + g[i - 1][0]) % mod;
            if (f[i][j] == abs(f[i - 1][0] + a[i])) g[i][j] = (g[i][j] + g[i - 1][0]) % mod;
            if (f[i - 1][0] == f[i - 1][1]) continue;
            if (f[i][j] == f[i - 1][1] + a[i]) g[i][j] = (g[i][j] + g[i - 1][1]) % mod;
            if (f[i][j] == abs(f[i - 1][1] + a[i])) g[i][j] = (g[i][j] + g[i - 1][1]) % mod;
        }
    }
    printf("%d\n", g[n][0]);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

  再给出官方题解的做法,还是很难想到的。

  事实上对于操作 $2$ 我们至多执行一次。假设执行了至少两次操作 $2$,我们关注最后执行操作 $2$ 的两个位置 $i$ 和 $j$ $(i<j)$。此时必然有 $c + a_i < 0$ 和 $c + a_j < 0$,否则完全可以用操作 $1$ 代替。对第 $i$ 个位置的操作变成操作 $1$,那么在第 $j$ 个位置操作前 $c$ 会变小,又因为 $c + a_j < 0$,因此对位置 $j$ 执行操作 $2$ 后 $c$ 就会变大。因此至多执行一次操作 $2$。

  那么对哪个位置执行操作 $2$ 呢?定义前缀和 $s_i = \sum\limits_{i=1}^{n}{a_i}$,则应该在 $x = \mathop{\arg\min}\limits_{i}\{s_i\}$ 处。

  证明:在位置 $x$ 执行操作 $2$ 后答案就是 $|s_x| + s_n - s_x$,又因为对于任意的 $i$ 都有 $s_i \geq s_x$,因此

$$
\begin{align*}
&|s_x| + s_n - s_x \\
=& |s_x| + s_n - s_i - (s_x - s_i) \\
\geq& |s_i| + s_n - s_i - (s_x - s_i) \\
\geq& |s_i| + s_n - s_i \\
\end{align*}
$$

  再考虑方案数。先考虑 $s_x \geq 0$ 的情况,显然方案数应该是 $2^n$。

  否则,先考虑 $i < x$ 的位置可以执行哪些操作,首先每一个位置都可以执行操作 $1$,而如果位置 $i$ 可以执行操作 $2$,那么就要保证 $c + a_i = |c + a_i|$,即保证 $s_i \geq 0$(否则最终答案会改变)。假设有 $c$ 个这样的位置。

  再考虑 $i > x$ 的位置,对位置 $x$ 执行操作 $2$ 后,因为 $|s_x| + s_i - s_x \geq s_x + s_i - s_x = s_i$,因此每个位置无论执行什么操作,结果都是非负的。

  因此最后的方案数是就是 $\sum\limits_{i=1}^{n}[s_i = s_x] \cdot 2^{c + n-i}$。

  AC 代码如下,时间复杂度为 $O(n)$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5, mod = 998244353;

LL s[N];
int p[N];

void solve() {
    int n;
    scanf("%d", &n);
    LL mn = 1e18;
    p[0] = 1;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", s + i);
        s[i] += s[i - 1];
        mn = min(mn, s[i]);
        p[i] = p[i - 1] * 2ll % mod;
    }
    if (mn >= 0) {
        printf("%d\n", p[n]);
        return;
    }
    int ret = 0;
    for (int i = 1, c = 0; i <= n; i++) {
        if (s[i] == mn) ret = (ret + 1ll * p[c] * p[n - i]) % mod;
        if (s[i] >= 0) c++;
    }
    printf("%d\n", ret);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Global Round 26 Editorial:https://codeforces.com/blog/entry/130252

  Codeforces Global Round 26 A~E:https://zhuanlan.zhihu.com/p/702528746

标签:geq,Version,int,value,leq,Magnitude,操作,test,C2
From: https://www.cnblogs.com/onlyblues/p/18246623

相关文章

  • This version of the Android Support plugin for IntelliJ IDEA or Android Studio c
    解决低版本的android导入高版本的工程7.2修改适配android4.2.11、setting.gradle保留rootProject.name=""和include‘:app’,其余注释//pluginManagement{//repositories{//gradlePluginPortal()//google()//mavenCentral()//}//......
  • CEC2013(python):六种算法(ABC、PSO、CSO、OOA、DBO、RFO)求解CEC2013
    一、六种算法简介1、人工蜂群算法(ArtificialBeeColonyAlgorithm,ABC)2、粒子群优化算法PSO3、鸡群优化算法CSO4、鱼鹰优化算法OOA5、蜣螂优化算法DBO6、红狐优化算法RFO二、6种算法求解CEC2013(1)CEC2013简介参考文献:[1]LiangJJ, QuBY, SuganthanPN......
  • CEC2017(Python):七种算法(PSO、RFO、DBO、HHO、SSA、DE、GWO)求解CEC2017
    一、7种算法简介1、粒子群优化算法PSO2、红狐优化算法RFO3、蜣螂优化算法DBO4、哈里斯鹰优化算法HHO5、麻雀搜索算法SSA6、差分进化算法DE7、灰狼优化算法GWO二、CEC2017简介参考文献:[1]Awad,N.H.,Ali,M.Z.,Liang,J.J.,Qu,B.Y.,&Suganthan,P.N.(2......
  • CEC2017(Python):七种算法(RFO、DBO、HHO、SSA、DE、GWO、OOA)求解CEC2017
    一、7种算法简介1、红狐优化算法RFO2、蜣螂优化算法DBO3、哈里斯鹰优化算法HHO4、麻雀搜索算法SSA5、差分进化算法DE6、灰狼优化算法GWO7、鱼鹰优化算法OOA二、CEC2017简介参考文献:[1]Awad,N.H.,Ali,M.Z.,Liang,J.J.,Qu,B.Y.,&Suganthan,P.N.(201......
  • 苹果WWDC24一文总结,携手OpenAi,开启Ai新篇章
    北京时间6月11日凌晨1点,苹果2024年全球开发者大会(WWDC)正式开幕。按照往年惯例,每年的WWDC大会,苹果都会将重心放在对新版系统的介绍上,本次也不例外,苹果发布了包括iOS18、iPadOS18、macOS15以及visionOS2等在内的一系列软件更新。除了例行的系统更新,发布会的最重头大戏就是AI......
  • Ton 区块链的官方 类ERC20-Token 智能合约代码-Transfer部分解析
    作者:林冠宏/指尖下的幽灵。转载者,请:务必标明出处。掘金:https://juejin.im/user/1785262612681997GitHub:https://github.com/af913337456/出版的书籍:《1.0-区块链DApp开发实战》《2.0-区块链DApp开发:基于公链》Ton区块链的官方类ERC20-Token智能合约代码-Trans......
  • Adobe Acrobat Pro DC2023软件安装教程、安装包下载
    软件简介AcrobatDC是一个功能强大的PDF编辑软件,它可以将任何纸质文件转换为可编辑的电子文件,用于传输、签署和分享,并且提供了一系列强大的功能来编辑PDF文档。软件下载复制链接在浏览器打开即可下载https://www.qqres.com/2248.html安装步骤1.打开解压后的文件夹,鼠......
  • C2. Magnitude (Hard Version)
    原题链接题解由于使用操作二会让负数变成正数,所以我们考虑让操作二在c最小且为负数的点使用在使用完操作二之后,之后的c肯定非负,所以在此之后两种操作都可以使用实施先判断存不存在c最小且为负数的点,然后再统计所有c最小且为负数的点的贡献code#include<bits/stdc++.h>usin......
  • 《DX12龙书》-第一个例程出现的报错:error: 应用程序请求的操作依赖于已缺失或不匹配的
    《DX12龙书》|《Introductionto3DGameProgrammingwithDirectX12》|《DirectX123D游戏开发实践》个人电脑环境Window11;VisualStudio2022出现问题主要原因:书中代码的环境是:Windows10;VS2015,在不同环境上运行难免会出现一些错误。问题一:C2102&要求左值错......
  • 逐飞串口助手——基于tc264的示波器使用
    一、下载逐飞串口助手解压文件夹中的seekfree_assistant-master.zip;解压成功后,点击逐飞助手V1.0.0.exe即可进入程序二、将示波器使用例程导入ADS开发平台1.解压文件夹中的Oscilloscopes_demo.zip2.打开ADS开发平台,点击file-import3.选择existingprojectsintowork......