P7519-[省选联考 2021 A/B 卷]滚榜【状压dp】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P7519


1|1题目大意

n个队伍,队伍之间按照得分从小到大排名,得分相同的按照编号从小到大排。开始时每个队伍有个初始得分ai,和一个额外分bi,主持人会按照bi不降的顺序让每个队伍的得分加上bi,并且要求每次加上后这个队伍都变成第一名。

已知每个队伍的初始分a和额外分的和m,求有多少种公布额外分的序列。

1n13,1m500,0ai104


1|2解题思路

显然地一点是我们考虑一个序列合法时bi的和的最小值,然后和m进行比较

开始思路时卡了,假设已经排好了一部分,我们需要把一个新的排在后面,此时会有两个限制:

  1. 这个队伍的得分ai+bi必须是已经公布的里面最大的(或相同的序号最小的)
  2. bi必须是已经公布的里面最大的。

显然记录上这两个限制进行的dp并不方便,考虑如何去掉一个限制,因为bi是我们可以任意调整的,并且要求递增,可以每次操作都让后面所有数字的bi都同时加值,这样就不需要考虑第二个限制了。

然后是第一个限制如何处理,注意到我们在刚刚的情况下,假设限制最后公布的一个是i,而下一个公布的是j,那么此时有bj=bi,所以此时两个数加上b之后的差值不变,所以直接拿aiaj就可以知道后面的bj要加上多少了。

那么做法已经显然了,设fs,i,j表示现在已经插入的数状态为sbi的和为i,目前最后一个公布的是j,然后O(n)转移即可。

时间复杂度:O(2nmn2),实际上很多状态是不会到达的,所以能过。


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=13; ll n,m,ans,a[N],c[1<<N],f[1<<N][501][N]; signed main() { scanf("%lld%lld",&n,&m); ll pos=0; for(ll i=0;i<n;i++){ scanf("%lld",&a[i]); if(a[i]>a[pos])pos=i; } f[0][0][pos]=1; ll MS=(1<<n); for(ll s=1;s<MS;s++)c[s]=c[s-(s&-s)]+1; for(ll s=0;s<MS;s++) for(ll k=0;k<=m;k++) for(ll i=0;i<n;i++){ if(!f[s][k][i])continue; for(ll j=0;j<n;j++){ if((s>>j)&1)continue; ll w=max(a[i]-a[j]+(j>i),0ll)*(n-c[s]); if(k+w>m)continue; f[s^(1<<j)][k+w][j]+=f[s][k][i]; } } for(ll i=0;i<=m;i++) for(ll j=0;j<n;j++) ans+=f[MS-1][i][j]; printf("%lld\n",ans); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15598342.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示