zoukankan      html  css  js  c++  java
  • [loj6433]最大前缀和

    考虑去枚举这个构成最大前缀和的集合$S$,那么限制分为两条:

    1.前$|S|$个元素都属于$S$,且任意非空前缀和都小于$sum(S)$(其中$sum(S)$表示$S$中元素之和)(这里的小于是避免统计重复,强制要求最长的前缀)

    2.后$n-|S|$个元素都不属于$S$,且最大前缀和为0(允许为空)

    令$f(S)$表示$S$中的元素最大前缀和为0(允许为空)的方案数,这个的必要条件为$sum(S)le 0$,同时在这样的条件下,对于序列最后一个数是无关的,因此$f(S)=sum_{xin S}f(S-x)$(这里$S-x$指去除$x$)

    对于第一个条件,也就是最小非空后缀和大于0,将$a_{i}$变为其相反数后,也就是最大非空后缀和小于0,但特别的,这个后缀不能等于全集(因为本来的前缀非空)

    先不考虑不能等于全集的条件,取反后用类似的方式求出$g(S)$(后缀和前缀是等价的),那么接下来再任意填上最后一个数即可,即$g(S)=sum_{xin S}g(S-x)$(类似背包的原理,要从后往前做)

    由此即可$o(n2^{n})$求出答案

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 2000005
     4 #define mod 998244353
     5 int n,ans,sum[N],g[N],f[N];
     6 int main(){
     7     scanf("%d",&n);
     8     for(int i=0;i<n;i++)scanf("%d",&sum[1<<i]);
     9     g[0]=f[0]=1;//g[S]表示S中所有数最小前缀和为0 
    10     for(int i=1;i<(1<<n);i++){
    11         int k=(i&(i-1));
    12         sum[i]=sum[k]+sum[i^k];
    13         if (sum[i]>0){
    14             for(int j=0;j<n;j++)
    15                 if (i&(1<<j))g[i]=(g[i]+g[i^(1<<j)])%mod;
    16         }
    17         if (sum[i]<=0){
    18             for(int j=0;j<n;j++)
    19                 if (i&(1<<j))f[i]=(f[i]+f[i^(1<<j)])%mod;
    20         }
    21     }
    22     for(int i=(1<<n)-1;i;i--)
    23         if ((i&(i-1))==0)g[i]=1;
    24         else{
    25             g[i]=0;
    26             for(int j=0;j<n;j++)
    27                 if (i&(1<<j))g[i]=(g[i]+g[i^(1<<j)])%mod;
    28         }
    29     for(int i=0;i<(1<<n);i++)ans=(ans+1LL*(sum[i]+mod)*g[i]%mod*f[(1<<n)-1-i])%mod;
    30     printf("%d",ans);
    31 }
    View Code
  • 相关阅读:
    【如何入门ACM】
    HDU
    HDU 6107 Typesetting
    bzoj 3223: Tyvj 1729 文艺平衡树
    51Nod 1781 跑的比谁都快
    51Nod 1331 狭窄的通道
    51Nod 1555 布丁怪
    hihocoder 1035 : 自驾旅行 III
    51Nod 1196 字符串的数量
    51Nod 1530 稳定方块
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14302617.html
Copyright © 2011-2022 走看看