zoukankan      html  css  js  c++  java
  • [PKUSC2018]最大前缀和(DP)

    题意:求一个序列随机打乱后最大前缀和的期望。

    考场上发现不管怎么设状态都写不出来,实际上只要稍微转换一下就好了。

    一个前缀[1..k]是最大前缀,当且仅当前面的所有后缀[k-1,k],[k-2,k],...,[1,k]都大于0,后面的所有前缀[k+1,k+2],[k+1,k+3],...,[k+1,n]全部不大于0。

    于是设f[S]表示S集合满足所有后缀大于0的排列数,g[S]表示S前缀不大于0的排列数,直接转移,最后答案就是所有集合(空集除外)的f乘上补集的g。

    不卡时BZOJ时间榜与码长榜 rank 1。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l),_=(r); i<=_; i++)
     4 using namespace std;
     5 
     6 const int N=1048577,mod=998244353;
     7 int n,ans,a[N],cnt[N],f[N],g[N],ll[N];
     8 inline void up(int &x,int y){ x+=y; if (x>=mod) x-=mod; }
     9 
    10 int main(){
    11     scanf("%d",&n); int S=(1<<n)-1; g[0]=1;
    12     rep(i,0,n-1) scanf("%d",&a[1<<i]);
    13     rep(s,1,S){
    14         int t=s&-s; cnt[s]=cnt[s^t]+a[t];
    15         if (!(s^t)) { f[s]=1; g[s]=(a[t]<=0); continue; }
    16         for (int p=s; p; p=p^t,t=p&-p){
    17             if (cnt[s^t]>0) up(f[s],f[s^t]);
    18             if (cnt[s]<=0) up(g[s],g[s^t]);
    19         }
    20     }
    21     rep(s,1,S) ans=(ans+1ll*f[s]*g[S^s]%mod*cnt[s])%mod;
    22     printf("%d
    ",(ans+mod)%mod);
    23     return 0;
    24 }
  • 相关阅读:
    软工人日常
    11.5
    11.4
    11.3
    11.2阅读笔记
    11.1阅读笔记
    10.31 异常
    10.30动手动脑
    10.29
    10.28
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9162247.html
Copyright © 2011-2022 走看看