codeforces713C(用第几大的数表示一个状态)

Problem - C - Codeforces

解题思路

先让\(a_{i}-i\),这样的话,就可以将问题转换成求最少操作数得到单调不减数列

\(dp[i][j]\)表示前i个数变成小于等于j最少需要多少步,所以接下来考虑\(dp[i+1][j]\)怎么来,和\(dp[i][j]\)相比,他多了一个\(a_{i+1}\),所以只需要让\(a_{i+1}\)等于\(j\)就行,也就是

\[dp[i+1][j]=dp[i][j]+|a_{i+1}-j| \]

光是这样还不够,还有可能是让前\(i\)个数小于等于\(j\)更优,也就是\(dp[i][j-1]\)的结果更优,所以就这样合并一下就有

\[dp[i][j]=min(dp[i-1][j]+|a_{i}-j|,dp[i][j-1]) \]

最终答案就是\(dp[n][n]\),考虑到j可以非常的大,所以可以对a进行排序,j表示第j小的数,这样可以省去大量的空间

代码

#include<bits/stdc++.h>
#define int long long 
#define inf 1e18
 
#define MOD 1000000007
using namespace std;

int dp[3005][3005]={0};
void solve(){
	int n;
	cin>>n;
	vector<int>a(n+1),b(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		a[i]=b[i]=a[i]-i;
	}
	sort(b.begin()+1,b.begin()+n+1);
	for(int i=1;i<=n;i++)
	{
		dp[i][0]=inf;
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=min(dp[i][j-1],dp[i-1][j]+abs(a[i]-b[j]));
		}
	}
	cout<<dp[n][n]<<endl;
}
 
signed main() {
    ios::sync_with_stdio(0);
    cout.tie(0),cin.tie(0);
    int test=1;
    while(test--)
    solve();
    return 0;
}
int 

反思总结

  • 对于dp的状态可以考虑用第几大的数表示一个状态
posted @ 2025-03-21 20:29  C微  阅读(21)  评论(0)    收藏  举报