1 条题解
-
0
自动搬运
来自洛谷,原作者为

白鲟
AFO|Und da warst Du搬运于
2025-08-24 22:30:39,当前版本为作者最后更新于2021-04-15 17:02:12,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
前言
纪念一下这场爆炸的省选唯一 AC 的题目。
同时是第一次在正式考场上 AC 动态规划。
同时是第一次在正式考场上 CE(还是本应 AC 的 Day1 T1)。
大概是本场第三简单的题。
应该比去年 Day2 T1 简单。
分析
看了一眼范围估计是状压。
开始分析的时候容易想到设计状态为 ,即前 位为 内元素、第 位为 、已选 总和为 、上一个 为 的方案总数,但始终甩不掉枚举 的和与上一个 的值的 循环。
冷静看题。发现只用求排名的总方案数,而与 分配方式无关。可以得到的启发是寻找 的最佳分配方式。
对于某一确定的排列方式 ,贪心地分配使得每个位置的 尽量小的方式易得:若当前的 大于 ,为了维护 不降,使得 ,否则 。
根据这一结论,直接使用全排列可以获得 60 pts 的好成绩。
回到状压。考虑对贡献进行简单变形:,如此可以甩掉枚举上一个 的值这一步。设 表示前 位为 内元素、第 位为 、已选总贡献为 的方案总数,在枚举状态的同时枚举下一个选的数,容易写出方程式。
最后统计 的和即可。
时间复杂度为 。可通过使用 枚举元素等方式略微卡常。
上述方法忽略的细节是相等时的按编号排序,实现时应注意。
代码
upd on 2021.4.24
根据 UOJ 数据修复了代码实现的一点小问题,目前在 UOJ 上可通过。
#include<algorithm> #include<cstdio> using namespace std; const int maxn=13,maxm=500; int n,m,all,t,a[maxn+1],no[1<<maxn|1]; long long f[1<<maxn|1][maxn+1][maxm+1],ans; inline int lowbit(int x) { return x&(-x); } int main() { scanf("%d%d",&n,&m); all=(1<<n)-1; a[0]=-1; for(int i=1;i<=n;++i) { scanf("%d",&a[i]); if(a[i]>a[t]) t=i; no[1<<(i-1)]=i; } for(int i=1;i<=n;++i) { int target=n*(a[t]-a[i]+(t<i)); if(target<=m) f[1<<(i-1)][i][target]=1; } for(int i=1;i<all;++i) { int popcount=0; for(int j=1;j<=maxn;++j) if(i&(1<<(j-1))) ++popcount; for(int t=i;t;t-=lowbit(t)) for(int sum=0;sum<=m;++sum) { int pos=no[lowbit(t)]; for(int j=1;j<=n;++j) if(!(i&(1<<(j-1)))) { int target=sum+(n-popcount)*max(0,(pos<j)+a[pos]-a[j]); if(target<=m) f[i|(1<<(j-1))][j][target]+=f[i][pos][sum]; } } } for(int i=0;i<=m;++i) for(int j=1;j<=n;++j) ans+=f[all][j][i]; printf("%lld",ans); return 0; }
- 1
信息
- ID
- 6684
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者