唐題。
分析
考慮一個數列 \([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;