挺有意思的一道题。
刚看到可能有好几种思路,按照 的大小填 ,或者按照下标顺序填等等。
试了几次之后 考虑按照 从小到大填入 ,设 为当前填了的最大的 ,由于题目的要求, 的所有数一定都用过()。所以状压记录值域的 位上有哪些数还没填,这里的值域指的仍然是 ,根据 和 可以推出 。
然后求逆序对的话对于值域的最后 位暴力计算,对于 的部分,设 则可以看成是一个询问 且 的点的数量,二维前缀和即可,复杂度 。
int n,m,b[5010],f[5010][512],a[5010];
unsigned short t[5010][5010];
inline void mian()
{
read(n,m),++m;
for(int i=1;i<=n;++i)read(a[i]),++t[i][a[i]],b[a[i]]=i;
for(int i=n;i>=1;--i)for(int j=1;j<=n;++j)t[i][j]+=t[i+1][j]+t[i][j-1]-t[i+1][j-1];
memset(f,127,sizeof(f)),f[0][(1<<m)-1]=0;
for(int i=1;i<=n;++i)
{
for(int j=1,pos;j<(1<<m);j+=2)
{
pos=i+m-__builtin_popcount(j)-1;
if(f[i-1][j]>=inf)continue;
for(int k=1;k+pos<=n&&k<=m;++k)
{
if(!(j>>(m-k)&1))break;
int x=0;
for(int l=0;l<m&&pos>l;++l)x+=(j>>l&1)&&b[pos-l]>b[pos+k];
Mmin(f[i][(j<<k|1)&((1<<m)-1)],f[i-1][j]+x+(pos>m?t[b[pos+k]+1][pos-m]:0));
}
for(int k=0;k<m&&k<pos;++k)
{
if(j>>k&1)continue;
int x=0;
for(int l=0;l<k;++l)x+=(j>>l&1)&&b[pos-l]>b[pos-k];
for(int l=k+1;l<m&&l<pos;++l)x+=(j>>l&1)&&b[pos-l]>b[pos-k];
Mmin(f[i][j|1<<k],f[i-1][j]+x+(pos>m?t[b[pos-k]+1][pos-m]:0));
}
}
}
write(f[n][(1<<m)-1]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现