这题显然的是dp
设计状态dp[u][i][j]为在前i个数中进行操作,swap次数不超过j次,前i个数的和最小是多少
对于第u个元素:
如果不将它放进前i个:dp[u][i][j]=dp[u-1][i][j]
如果将它放进前i个,一个显然的结论是,要使得交换次数最少,本来在序列中靠前的那些数最后在前i个数中也应靠前
所以应该将第u个数放在第i个,dp[u][i][j]=dp[u-1][i-1][j-(u-i)]
两者取min即可
注意要用滚动数组防超空间
(PS:下面的代码交上去死活WA在test1,然而样例是过的,在网上找了一个AC程序拍了一遍,应该是对的)
#include <bits/stdc++.h>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define LL long long
#define ld long double
#define Pair pair<int,int>
#define LOWBIT(x) x & (-x)
using namespace std;
const int INF=0x7ffffff;
const int MOD=1e9+7;
int dp[2][155][30000];
int n,k,s;
int a[200],sum[200];
int main ()
{
//freopen ("test.in","r",stdin);
//freopen ("test.out","w",stdout);
int u,i,j;
scanf("%d%d%d",&n,&k,&s);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
int p1=0,p2=1;
int ans=INF;
for (i=1;i<=min(u,k);i++)
for (j=0;j<=min(s,n*n);j++)
dp[p2][i][j]=a[1];
swap(p1,p2);
for (u=2;u<=n;u++)
{
for (i=1;i<=min(u,k);i++)
for (j=0;j<=min(s,n*n);j++)
{
dp[p2][i][j]=INF;
if (u>i) dp[p2][i][j]=dp[p1][i][j];
if (j-(u-i)>=0) dp[p2][i][j]=min(dp[p2][i][j],dp[p1][i-1][j-(u-i)]+a[u]);
if (i==k && (j==n*n || j==s)) ans=min(ans,dp[p2][i][j]);
}
swap(p1,p2);
}
printf("%d\n",ans);
return 0;
}
反思:设计dp状态的时候,设置为“不超过i”而不是“正好是i”dp时可以省一维度