您的位置:首页 > 运维架构

Codeforces Round #327 (Div. 1) D. Top Secret Task

2015-11-02 22:01 489 查看
题意: 给了一个n,k,s,和一个数组,求使用小于s次的交换使得前k个整数的和尽可能的小,交换指的的是相邻的两个数交换,

首先考虑 如果最小的k个数全部再最后面,那么至少要花费 ( n - k + 1 + n)*k/2 - (( k + 1 ) * k / 2) 这么多下才能把这k个数搬运到最前面,也就是说如果s他大于等于这个数 那么答案一定是最小的那k个数,

否则进行下面的做法

假设前k个数 在最初的 那个数组中的下标分别是L1<L2<...<Lk,肯定被选中的那k个数他们的相对位置肯定是不变得,如果变了会增加交换的次数

那么我们就假设就是最初给的那个数组的下标L1 L2 L3 L4..Lk 那么所要的交换此时就是 T=L1-1+L2-2+...Lk-k我们知道这个要小于等于S

于是得到 L1+L2+...+Lk<=S+(1+k)*k/2,采用dp[i][j][p]表示 前i个数 选了j个他们的下标和为p的最小值,dp[i][j][p]=min(dp[i-1][j][p],dp[i-1][j-1][p-i]+A[i])

数据太大 采用滚动数组,

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <string.h>
using namespace std;
const int maxn=155;
const int INF=2147483647;
int A[maxn];
int dp[2][maxn][maxn*maxn*2];
int main()
{

int n,k,s;
scanf("%d%d%d",&n,&k,&s);
for(int i=1; i<=n; i++)
scanf("%d",&A[i]);
if(k==n)
{
int sum=0;
for(int i=1; i<=n; i++)
sum+=A[i];
printf("%d\n",sum);return 0;
}
if( s >= ( n - k + 1 + n)*k/2 - (( k + 1 ) * k / 2 ) )
{
sort(A+1,A+1+n);
int sum=0;
for(int i=1; i<=k; i++)
sum+=A[i];
printf("%d\n",sum);return 0;
}
int S=s+(k+1)*k/2;
int cur=0,per=1;
for(int i=1; i<=k; i++)
for(int j=0; j<=S; j++)dp[0][i][j]=INF;

for(int i=1; i<=n; i++)
{
cur^=1;
per^=1;
for(int j=1; j<=k; j++)
{
for(int a=0; a<=S; a++)
{
dp[cur][j][a]=dp[per][j][a];
if(a>=i&&dp[per][j-1][a-i]!=INF){
dp[cur][j][a]=min(dp[per][j-1][a-i]+A[i],dp[cur][j][a]);
}
}
}
}
int ans=INF;
for(int i=0; i<=S; i++)
ans=min(dp[cur][k][i],ans);
printf("%d\n",ans);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: