Codeforces #590D: Top Secret Task 题解

来源:互联网 发布:linux怎么用vi创建文件 编辑:程序博客网 时间:2024/05/17 07:54

这题显然的是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时可以省一维度