洛谷 - P5369
唐题。
分析
考虑一个数列 \([1,i]\) 前缀最大的充要条件,当且仅当:
- \(\forall k \in [1,i]\),满足 \(\sum\limits_{j=k}^i a_j \ge 0\)
- \(\forall k \in (i,n]\),满足 \(\sum\limits_{j=i+1}^j a_j < 0\)
考虑对满足第一/二种条件的排列进行计数。
令 \(f_{S}\) 为当前被使用的状态为 \(S\),从前往后填到 \(popcount(S)\) 位的方案数,转移有:
\[f_{S} \rightarrow f_{S+T},T\notin S,sum_S \ge 0
\]
第二种条件同理。
代码
n=rd();
for(int i=0;i<n;i++)
a[i]=rd(),f[1<<i]=1;
int all=(1<<n)-1;
for(int S=1;S<=all;S++)
for(int i=0;i<n;i++)
if(S>>i&1)
sum[S]+=a[i];
g[0]=1;
for(int S=1;S<=all;S++){
if(sum[S]>=0){
for(int i=0;i<n;i++)
if(!(S>>i&1))
f[S|(1<<i)]=(f[S|(1<<i)]+f[S])%mod;
}
else{
for(int i=0;i<n;i++)
if(S>>i&1)
g[S]=(g[S]+g[S^(1<<i)])%mod;
}
}
int ans=0;
for(int S=1;S<=all;S++){
ans=(ans+f[S]*g[all^S]%mod*sum[S]%mod+mod)%mod;
}
cout<<ans<<endl;