P7650 题解
非常好题目,第一步都想不出来。
可以观察出来最优方案必定是从大往小将
这里是这道题最重要的一步:相对位置的变化非常不好描述,考虑将所有数固定。一次操作改为:不影响其他其他数的位置,将一个数放到任意位置,一个位置上可能有多个数。稍微分析一下可以发现,如果从大到小考虑的话,那么一个数的实际位置就是在他之前的它小的数。这个实际位置的计算还是有些问题的,比如假设当前数是
有了这种计算方式,我们可以设计
我们考虑第二种决策,即不改变
构造方案的话,倒推就行了。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10,inf=0x3f3f3f3f;
int n,a[maxn],f[maxn][maxn],g[maxn][maxn],t[maxn],pos[maxn];
int sum[maxn][maxn],cnt[maxn][maxn];
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],
t[i]=a[i];
sort(t+1,t+1+n);
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(t+1,t+1+n,a[i])-t;
a[i]=n+1-a[i];
pos[a[i]]=i;
}
a[n+1]=n+1;
for(int i=1;i<=n+1;i++)
{
for(int j=1;j<=n+1;j++)sum[i][j]=sum[i-1][j],cnt[i][j]=cnt[i-1][j];
for(int k=a[i];k<=n+1;k++)sum[i][k]+=a[i],cnt[i][k]++;
}
memset(f,0x3f,sizeof f);
f[n+1][n+1]=0;
for(int x=n;x>=0;x--)
for(int q=n+1;q>=1;q--)
if(f[x+1][q]!=inf)
{
if(!x)continue;
int p=pos[x];
if(f[x][q]>f[x+1][q]+cnt[p-1][x-1]+cnt[q-1][x-1]+2)
g[x][q]=q,f[x][q]=f[x+1][q]+cnt[p-1][x-1]+cnt[q-1][x-1]+2;
if(p<q&&f[x][p]>f[x+1][q]+(cnt[q-1][x-1]-cnt[p][x-1])*x-(sum[q-1][x-1]-sum[p][x-1]))
g[x][p]=q,f[x][p]=f[x+1][q]+(cnt[q-1][x-1]-cnt[p][x-1])*x-(sum[q-1][x-1]-sum[p][x-1]);
}
vector< int > Ans;
int mn=inf,q=0;
for(int i=1;i<=n+1;i++)if(f[1][i]<mn)mn=f[1][i],q=i;
for(int x=1;x<=n;x++)Ans.push_back(q),q=g[x][q];
reverse(Ans.begin(),Ans.end());
vector< pair<int,int> > val;
for(int i=0;i<Ans.size();i++)
if(Ans[i]!=pos[n-i])
{
int pnow=pos[n-i],qnow=Ans[i];
int rp=cnt[pnow-1][n-i-1]+1,rq=cnt[qnow-1][n-i-1]+1;
for(int j=0;j<i;j++)rp+=Ans[j]<pnow;
for(int j=0;j<i;j++)rq+=Ans[j]<qnow;
if(rp==n+1)rp--;
if(rq==n+1)rq--;
val.push_back({rp,rq});
}
cout<<val.size()<<'\n';
for(auto [x,y]:val)cout<<x<<' '<<y<<'\n';
}
本文作者:_kkio
本文链接:https://www.cnblogs.com/hikkio/p/17793210.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步