LOJ#6433. 「PKUSC2018」最大前缀和 状压DP

思路比较自然.  

开始的时候有一个地方糊涂了,后来想清楚就好了.   

这里注意一个地方:  

令 $f[S]$ 表示 $S$ 集合的所有排列中 sum(S) 为最大值的排列数.    

然后转移 $f[S]$ 的时候要把新的元素放到序列开头,因为放到结尾的话前面的前缀可能非常小,导致到达不了结尾. 

code: 

#include <bits/stdc++.h>  
#define N 23  
#define ll long long    
#define mod 998244353   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;    
int sum[1<<N],f[1<<N],g[1<<N],ge[1<<N],cn[N],a[N],n; 
inline int lowbit(int x) { return x&(-x); }       
int main() 
{ 
    // setIO("input"); 
    for(int i=1;i<N;++i) cn[i]=1<<(i-1),ge[cn[i]]=i;               
    scanf("%d",&n); 
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);    
    g[0]=f[0]=1;    
    for(int S=1;S<cn[n+1];++S) 
        sum[S]=sum[S-lowbit(S)]+a[ge[lowbit(S)]];          
    for(int S=1;S<cn[n+1];++S) 
    { 
        int flag=0; 
        for(int j=1;j<=n;++j) 
        {
            if(S&cn[j]) 
            {   
                if(sum[S]<0)  (g[S]+=g[S^cn[j]])%=mod;   
                if(sum[S^cn[j]]>=0)                  
                    (f[S]+=f[S^cn[j]])%=mod,flag=-1000;   
                ++flag; 
            }                      
        } 
        if(flag==1) f[S]=1;  
    }         
    int ans=0; 
    int tot=cn[n+1]-1;       
    for(int S=1;S<cn[n+1];++S) 
    { 
        (ans+=(ll)((ll)f[S]*sum[S]%mod*g[tot-S]%mod+mod)%mod)%=mod; 
    }
    printf("%d\n",ans); 
    return 0; 
}

  

posted @ 2020-05-27 16:37  EM-LGH  阅读(166)  评论(0编辑  收藏  举报