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


    题意: 给了一个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
    ",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
    ",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
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    左眼右眼
    Mac 的“任务管理器” —— 活动监视器
    [分享] VIM 常用命令及游戏练级
    iOS 7 如何关闭已打开的应用(App)
    iPhone 如何设置彩信 ?
    JavaScript —— attachEvent 方法的使用
    习惯&感恩
    MySQL 基础 备份和恢复
    Python 数据结构 树
    Python 正在表达式
  • 原文地址:https://www.cnblogs.com/Opaser/p/4931563.html
Copyright © 2020-2023  润新知