Codeforces #590D: Top Secret Task 题解

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值