[LOJ6433]最大前缀和
2024-09-22 00:35:38
深刻感受到自己的水平和机房里的其他人相差甚远,他们都是随手秒这个题的...
$n$很小,考虑状压DP
当一个序列在某个位置取到最大前缀和后,意味着如果把后面的数抽出来单独成序列,那么它的每个前缀和都$\leq0$,要不然就可以取到更大的前缀和了
令$s_i$表示状态为$i$的数的和,$f_i$表示选状态为$i$的数且最大前缀和$=s_i$的方案数,$g_i$表示选状态为$i$的数且每个前缀和都$\leq0$的方案数,那么答案就是$\sum\limits_is_if_ig_{mx-i}$
如果$s_i\gt0$,那么我们在$i$这个状态代表的序列前面加任何一个数,新的序列的最大前缀和肯定是总和,所以我们有转移$f_{j\cup i}\gets f_i(i\cap j=\varnothing)$
如果$s_i\leq0$,那么我们在$i$这个状态代表的序列末尾删除一个数得到的序列仍然满足条件,所以我们有转移$g_i\gets g_{i-j}(i\cap j\ne\varnothing)$
总时间复杂度$O(n2^n)$
#include<stdio.h> const int maxn=1048576,mod=998244353; typedef long long ll; int a[20],s[maxn],f[maxn],g[maxn]; void inc(int&a,int b){(a+=b)%=mod;} int main(){ int n,i,j,mx,ans; scanf("%d",&n); for(i=0;i<n;i++)scanf("%d",a+i); mx=1<<n; for(i=0;i<mx;i++){ for(j=0;j<n;j++){ if(i>>j&1)s[i]+=a[j]; } } g[0]=1; for(i=0;i<mx;i++){ if(s[i]<=0){ for(j=0;j<n;j++){ if(i>>j&1)inc(g[i],g[i^(1<<j)]); } } } for(i=0;i<n;i++)f[1<<i]=1; for(i=0;i<mx;i++){ if(s[i]>0){ for(j=0;j<n;j++){ if(~i>>j&1)inc(f[i^(1<<j)],f[i]); } } } ans=0; for(i=0;i<mx;i++)inc(ans,s[i]*(ll)f[i]%mod*(ll)g[(mx-1)^i]%mod); inc(ans,mod); printf("%d",ans); }
最新文章
- 小猪cms之怎样查询绑定的微网站模板
- noi 2728 摘花生
- 【使用git】初识git
- 分享一个Mongodb PHP封装类
- android:layout_weight属性详解(转)
- Quartus II Error总结与解答
- iOS开发——网络Swift篇&;NSURLSession加载数据、下载、上传文件
- 自己实现的android树控件,android TreeView
- Disruptor框架
- rgbdslam_v2安装并使用
- ListView 分页 排序、编辑、插入和删除
- PHP array_filter() 函数
- Linux命令 用户管理命令
- 前端入门16-JavaScript进阶之EC和VO
- 如何查看电脑已连接的WiFi密码
- 区块链教程(二):比特币、区块链、以太坊、Hyperledger的关系
- RESTful API学习Day2 - Django REST framework
- LVOOP设计模式在路上(二)-- 策略模式
- Mybatis中resultType理解
- 基于开源SuperSocket实现客户端和服务端通信项目实战