CF590D Top Secret Task

CF590D Top Secret Task

题目描述

有n个数,有s次操作,每次操作可以交换两个相邻的数,现在要求通过s次操作,使前k个数的和最小,输出这个最小的和
n,k,s(1<=k<=n<=150,1<=s<=1e9)

Solution

容易发现虽然S很大

但只需要n*(n-1)/2次操作就可以把这个序列排有序

考虑S比n*(n-1)/2次操作小的时候

很显然,如果前J个数已经排好,则第i个数要放就一定换到第j+1位

由此DP就行,滚动数组优化空间

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    int f = 1,x = 0;
    char ch;
    do
    {
        ch = getchar();
        if(ch == '-') f = -1; 
    }while(ch < '0'||ch > '9');
    do
    {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();    
    }while(ch >= '0'&&ch <= '9');
    return f*x;    
} 

int n,K,s;
int a[150 + 10];
long long dp[2][150 + 10][150*150 + 10];

int main()
{
    while(~scanf("%d%d%d",&n,&K,&s))
    {
        for(int i=1;i<=n;i++) a[i] = read();
        if(s >= n*(n-1)/2)
        {
            sort(a+1,a+n+1);
            long long sum = 0;
            for(int i=1;i<=K;i++) sum += a[i];
            cout << sum << endl;
            continue;
        }
        memset(dp,127,sizeof(dp));
        dp[0][0][0] = 0;
        for(int i=1;i<=n;i++)
        {
            int cur = i&1;
            dp[cur][0][0] = 0;
            for(int j=1;j<=i;j++)
            {
                for(int k=0;k<=i*j;k++)
                {
                    dp[cur][j][k] = dp[cur^1][j][k];
                    if(k >= (i-j)) 
                        dp[cur][j][k] = min(dp[cur][j][k],dp[cur^1][j-1][k-(i-j)] + a[i]);
                //    cout << i << " " << j << " " << k << " " << dp[cur][j][k] << endl;
                }
            }
        }
        long long ans = 1<<30;
        for(int i=0;i<=s;i++) ans = min(ans , dp[n&1][K][i]);
        cout << ans << endl;
    }
}

 

posted @ 2020-10-16 22:03  wlzs1432  阅读(116)  评论(0编辑  收藏  举报