zoukankan      html  css  js  c++  java
  • [LOJ 6433][PKUSC 2018]最大前缀和

    [LOJ 6433][PKUSC 2018]最大前缀和

    题意

    给定一个长度为 (n) 的序列, 求把这个序列随机打乱后的最大前缀和的期望乘以 (n!) 后对 (998244353) 取膜后的值.

    前缀和不能为空.

    (nle 20).

    题解

    首先这个期望显然是逗你玩的...只是计数而已

    然后我们把一个序列拆成两部分, 一部分前缀和都不大于总和, 一部分前缀和都不大于 (0). 那么显然这样的一个序列的最大前缀和就是第一部分的和. 我们只要知道有多少个这样的序列就好了.

    后面的做法感觉有点意思

    我们用两个DP分别求解序列的某个子集组成两个部分的方案数量. 如果当前集合的和大于 (0) 那么显然不能用来组成第二部分, 但是我们可以在这个集合产生的合法第一部分的前面加一个值来组成新的第一部分. 而如果当前集合的和不大于 (0), 那么它只能用于构成第二部分, 而且我们可以断定如果在这个集合中钦定某个值放在最后, 那么只要剩下的值能构成合法的第二部分, 新的序列也能构成合法的第二部分.

    最后枚举那些值在第一部分, 剩下值丢给第二部分, 卷起来就可以了.

    参考代码

    #include <bits/stdc++.h>
    
    const int MAXN=21;
    const int MOD=998244353;
    const int MAXL=(1<<20)|3;
    
    int n;
    int a[MAXN];
    int dp1[MAXL];
    int dp2[MAXL];
    int sum[MAXL];
    
    inline int LowBit(int);
    
    int main(){
    	scanf("%d",&n);
    	dp2[0]=1;
    	for(int i=0;i<n;i++){
    		scanf("%d",a+i);
    		dp1[1<<i]=1;
    		sum[1<<i]=a[i];
    	}
    	for(int s=1;s<(1<<n);s++){
    		if(s!=LowBit(s))
    			sum[s]=sum[s^LowBit(s)]+sum[LowBit(s)];
    		if(sum[s]>0){
    			for(int i=0;i<n;i++)
    				if((s&(1<<i))==0)
    					(dp1[s^(1<<i)]+=dp1[s])%=MOD;
    		}
    		else{
    			for(int i=0;i<n;i++)
    				if((s&(1<<i))!=0)
    					(dp2[s]+=dp2[s^(1<<i)])%=MOD;
    		}
    	}
    	int ans=0;
    	for(int s=1;s<(1<<n);s++)
    		(ans+=1ll*sum[s]*dp1[s]%MOD*dp2[((1<<n)-1)^s]%MOD)%=MOD;
    	printf("%d
    ",ans<0?ans+MOD:ans);
    	return 0;
    }
    
    inline int LowBit(int x){
    	return x&-x;
    }
    
    

  • 相关阅读:
    Oracle Instant Client(即时客户端) 安装与配置
    Windows 下 Toad 如何使用 Oracle instantclient 32位客户端
    Oracle 内存(SGA,PGA)详细介绍
    深入解析Oracle 10g中SGA_MAX_SIZE和SGA_TARGET参数的区别和作用
    Android中的Touch事件
    Activity源码简要分析总结
    Android中的Interpolator
    Android 触摸手势基础 官方文档概览
    Android中View的绘制过程 onMeasure方法简述 附有自定义View例子
    Android TextView走马灯效果
  • 原文地址:https://www.cnblogs.com/rvalue/p/10934984.html
Copyright © 2011-2022 走看看