P5369 [PKUSC2018]最大前缀和

Posted hs-black

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5369 [PKUSC2018]最大前缀和相关的知识,希望对你有一定的参考价值。

状态压缩

P5369

题意:求所有排列下的最大前缀和之和

一步转化: 求最大前缀和的前缀由数集S组成的方案数, 统计答案时直接乘上sum(S)即可

考虑最大前缀和的性质:

设最大前缀和为sum[i]

  1. 到i的后缀均为正数
  2. i后的前缀均为负数

令sum[i] = 集合 i 内所有数的和。

令f[i] = 集合 i内的数组成的排列,最大前缀和 = sum[i]的方案数。

令g[i] = 集合 i内的数组成的排列,所有的最大前缀和都 < 0 的方案数。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 25;
const int P = 998244353;
int n, a[N];
int f[1050050], g[1050050];
int sum[1050050];
inline int to(int x) 
    return 1 << x;

int main() 
    cin >> n; int all = to(n) - 1;
    for (int i = 1;i <= n; i++) 
    cin >> a[i], f[to(i-1)] = 1, sum[to(i-1)] = a[i];
    for (int i = 1;i <= all; i++) 
            sum[i] = sum[(i & -i)] + sum[i ^ (i & -i)];
    g[0] = 1;
    for (int i = 0;i < all; i++) 
        if (sum[i] >= 0) 
            for (int j = 1;j <= n; j++) 
                if (!(i & to(j-1))) 
                    f[i | to(j-1)] = ((long long)f[i] + f[i | to(j-1)]) % P;
        
        else 
            for (int j = 1;j <= n; j++) 
                if (i & (to(j-1))) 
                    g[i] = ((long long)g[i] + g[i ^ to(j-1)]) % P;
        
    
    long long ans = 0;
    for (int i = 1;i <= all; i++)
        ans = (ans + (long long)f[i] * g[all^i] % P * sum[i] % P) % P;
    cout << (ans % P + P) % P << endl;
    return 0;

以上是关于P5369 [PKUSC2018]最大前缀和的主要内容,如果未能解决你的问题,请参考以下文章

[PKUSC2018]最大前缀和(DP)

loj#6433. 「PKUSC2018」最大前缀和(状压dp)

Loj#6433「PKUSC2018」最大前缀和(状态压缩DP)

Loj 6433. 「PKUSC2018」最大前缀和 (状压dp)

「PKUSC2018」神仙的游戏

loj6436PKUSC2018神仙的游戏