zoukankan      html  css  js  c++  java
  • [PKUSC2018]最大前缀和——状压DP

    题目链接:

    [PKUSC2018]最大前缀和

    设$f[S]$表示二进制状态为$S$的序列,任意前缀和都小于等于$0$的方案数。

    设$g[S]$表示二进制状态为$S$的序列是整个序列的最大前缀和的方案数。

    设$sum[S]$表示二进制状态为$S$的序列的每个数的和。

    那么答案就是$sumlimits_{S=1}^{2^n-1}sum[S]*g[S]*f[(2^n-1)-S]$。

    对于$f[S]$,转移相当于在序列前面加一个数,只有当前集合中数的和小于等于$0$时可以转移。

    对于$g[S]$,只能从和大于$0$的子集转移过来。

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int mod=998244353;
    int sum[3000000];
    int f[3000000];
    int g[3000000];
    int v[3000000];
    int n;
    int ans;
    int mask;
    void add(int &x,int y)
    {
    	x+=y;
    	if(x>mod)x-=mod;
    }
    int main()
    {
    	scanf("%d",&n);
    	mask=(1<<n)-1;
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&v[1<<(i-1)]);
    	}
    	for(int i=1;i<=mask;i++)
    	{
    		sum[i]=sum[i-(i&-i)]+v[i&-i];
    	}
    	f[0]=1;
    	for(int i=1;i<=n;i++)
    	{
    		g[1<<(i-1)]=1;
    	}
    	for(int i=1;i<=mask;i++)
    	{
    		if(sum[i]>0)
    		{
    			for(int j=i^mask;j;j-=j&-j)
    			{
    				int k=j&-j;
    				add(g[i|k],g[i]);
    			}
    		}
    		else
    		{
    			for(int j=i;j;j-=j&-j)
    			{
    				int k=j&-j;
    				add(f[i],f[i^k]);
    			}
    		}
    	}
    	for(int i=1;i<=mask;i++)
    	{
    		ans=(ans+1ll*g[i]*f[mask^i]%mod*sum[i]%mod)%mod;
    	}
    	printf("%d",(ans%mod+mod)%mod);
    }
  • 相关阅读:
    digitalpersona 开发
    Task 暂停与继续
    IQueryable 和 IEnumerable(二)
    SpringBoot Redis 订阅发布
    @Formula
    Aop 简单实例
    幂等 zuul的Filter实现
    C# async await 举个栗子
    Integer 类和 int 的区别
    TCP和UDP的区别以及各自应用
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10942319.html
Copyright © 2011-2022 走看看