P7519 [省选联考 2021 A/B 卷] 滚榜 题解
哎,考场上面连题都没有读懂,基本上把这次省选葬了。
主要是讲思考的思路。
考虑到数据范围很小,
进行状态设计。
既然是状压不可能没有
因为我们
剩下的一个比较好想的做法是,保存上一个人的
暴力即为暴力转移,时间复杂度
注意到我们统计的是排名的方案数,跟具体的
考虑将这一维删去,也就是说我们需要通过一些操作使得这一维的信息能够被表示或者忽略。
被表示估计不太行。注意到
注意到
具体想法是,我们将
也许这个东西叫做费用提前计算?
考虑实现,预处理一个数组
#include<bits/stdc++.h>
using namespace std;
int lowbit(int x){return x&(-x);}
int popcount(int x){int ans=0;while(x) x-=lowbit(x),++ans;return ans;}
int dp[(1<<13)+5][14][505],n,m,a[14],c[14][14];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) c[i][j]=max(0,a[i]-a[j]+int(i<j)),c[0][j]=max(c[0][j],c[i][j]);
dp[0][0][0]=1;
for(int S=0;S<(1<<n);++S)
{
if(S==lowbit(S))
{
int pos=0;
for(int i=1;i<=n;++i) if((S>>(i-1))&1 && (pos=i)) break;
if(n*c[0][pos]<=m) dp[S][pos][n*c[0][pos]]=1;
}
else
{
for(int i=1;i<=n;++i)
{
if((S>>(i-1))&1)
{
int T=S^(1<<(i-1));
int v=i;
for(int j=1;j<=n;++j)
{
if((T>>(j-1))&1)
{
int u=j;
int pct=n-popcount(T);
for(int k=c[u][v]*pct;k<=m;++k) dp[S][v][k]+=dp[T][u][k-c[u][v]*pct];
}
}
}
}
}
}
long long ans=0;
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) ans+=dp[(1<<n)-1][i][j];
printf("%lld",ans);
return 0;
}