zoukankan      html  css  js  c++  java
  • 【PKUSC2018】【loj6433】最大前缀和 状压dp

    这题吼啊...

    然而还是想了$2h$,写了$1h$。

    我们发现一个性质:若一个序列$p$能作为前缀和,那么在序列$p$中,包含序列$p$最后一个数的所有子序列必然都是非负的。

    那么,我们

    令$f[i]$表示状态$i$中所有数字全部作为前缀和的方案数。

    令$g[i]$表示状态$i$中所有数字所组合成的任意排列中,前缀和永远为负数的方案数。

    令$s[i]$表示状态$i$中所有数字之和。

    ps:若i的第j个二进制位为$1$,则表示状态$i$中,选择了数字$a_j$。($a$序列的下表为$0$到$n-1$)

     

    通过冷静分析,不难得出:

    $s[i]$很好求

    $f[i]=sum_{(2^j and i)=2^j∩s[i-2^j]+a[j]≥0} f[i-2^j]$

    $g[i]=sum_{(2^j and i)=2^j∩s[i-2^j]+a[j]<0} g[i-2^j]$

    显然$f[0]=g[0]=1$。

    统计答案时,分前缀和$≥0$,前缀和$<0$两类讨论。

    当前缀和$≥0$时

    $ans1=sum_{i=1}^{2^n-1} s[i] imes f[i] imes g[2^n-1-i] $

    当前缀和<0时

    $ans2=sum_{j=0}^{n=1} sum_{i=0} (a[j]+s[i]) imes f[i] imes g[2^n-1-i-2^j] [(2^j and i=0)∩s[i]<0∩s[i]>-a[j]]$

    最终所求答案即$ans1+ans2$。

    然后就完结了。

    时间复杂度为$O(n imes 2^n)$。

     1 #include<bits/stdc++.h>
     2 #define M 20
     3 #define L long long
     4 #define MOD 998244353
     5 using namespace std;
     6 
     7 L f[1<<M]={0},g[1<<M]={0},a[M]={0},he[1<<M]={0};
     8 
     9 int main(){
    10     int n,m; scanf("%d",&n); m=1<<n;
    11     for(int i=0;i<n;i++) cin>>a[i];
    12     for(int i=0;i<m;i++)
    13     for(int j=0;j<n;j++) 
    14     if(i&(1<<j)) he[i]+=a[j];
    15     f[0]=1; 
    16     for(int i=1;i<m;i++){
    17         for(int j=0;j<n;j++)
    18         if((i&(1<<j))&&he[i^(1<<j)]+a[j]>=0){
    19             f[i]=(f[i]+f[i^(1<<j)])%MOD;
    20         }
    21     }
    22     for(int i=0;i<n;i++) a[i]=-a[i];
    23     for(int i=0;i<m;i++) he[i]=-he[i];
    24     g[0]=1;
    25     for(int i=1;i<m;i++){
    26         for(int j=0;j<n;j++)
    27         if((i&(1<<j))&&he[i^(1<<j)]+a[j]>0){
    28             g[i]=(g[i]+g[i^(1<<j)])%MOD;
    29         }
    30     }
    31     for(int i=0;i<n;i++) a[i]=-a[i];
    32     for(int i=0;i<m;i++) he[i]=-he[i];
    33     L ans=0;
    34     for(int j=0;j<n;j++) if(a[j]<0){
    35         //f[1<<j]=1;
    36         for(int i=0;i<m;i++)
    37         if((i&(1<<j))==0){
    38             if(he[i]<0||he[i]>-a[j]) continue;
    39             int hh=(m-1)^i^(1<<j);
    40             ans=(ans+(a[j]+he[i])*f[i]%MOD*g[hh]%MOD+MOD)%MOD;
    41         }
    42     }
    43     for(int i=0;i<m;i++)
    44     ans=(ans+f[i]*he[i]%MOD*g[(m-1)^i]%MOD+MOD)%MOD;
    45     cout<<ans<<endl;
    46 }
    47     
  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9170243.html
Copyright © 2011-2022 走看看