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

    状态压缩

    P5369

    题意:求所有排列下的最大前缀和之和

    一步转化: 求最大前缀和的前缀由数集S组成的方案数, 统计答案时直接乘上sum(S)即可

    考虑最大前缀和的性质:

    设最大前缀和为sum[i]

    1. 到i的后缀均为正数
    2. i后的前缀均为负数

    令sum[i] = 集合 i 内所有数的和。

    令f[i] = 集合 i内的数组成的排列,最大前缀和 = sum[i]的方案数。

    令g[i] = 集合 i内的数组成的排列,所有的最大前缀和都 < 0 的方案数。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 25;
    const int P = 998244353;
    int n, a[N];
    int f[1050050], g[1050050];
    int sum[1050050];
    inline int to(int x) {
    	return 1 << x;
    }
    int main() {
    	cin >> n; int all = to(n) - 1;
    	for (int i = 1;i <= n; i++) 
    	cin >> a[i], f[to(i-1)] = 1, sum[to(i-1)] = a[i];
    	for (int i = 1;i <= all; i++) 
    			sum[i] = sum[(i & -i)] + sum[i ^ (i & -i)];
    	g[0] = 1;
    	for (int i = 0;i < all; i++) {
    		if (sum[i] >= 0) {
    			for (int j = 1;j <= n; j++) 
    				if (!(i & to(j-1))) 
    					f[i | to(j-1)] = ((long long)f[i] + f[i | to(j-1)]) % P;
    		}
    		else {
    			for (int j = 1;j <= n; j++) 
    				if (i & (to(j-1))) 
    					g[i] = ((long long)g[i] + g[i ^ to(j-1)]) % P;
    		}
    	}
    	long long ans = 0;
    	for (int i = 1;i <= all; i++)
    		ans = (ans + (long long)f[i] * g[all^i] % P * sum[i] % P) % P;
    	cout << (ans % P + P) % P << endl;
    	return 0;
    }
    
  • 相关阅读:
    laravel5.3统计 withCount()方法的使用
    laravel whereDate()方法的使用
    C语言I博客作业11
    C语言I博客作业10
    C语言I博客作业09
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
  • 原文地址:https://www.cnblogs.com/Hs-black/p/11626107.html
Copyright © 2011-2022 走看看