Codeforces Round #218 (Div. 2) E. Subway Innovation

E. Subway Innovation
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Berland is going through tough times — the dirt price has dropped and that is a blow to the country's economy. Everybody knows that Berland is the top world dirt exporter!

The President of Berland was forced to leave only k of the currently existing n subway stations.

The subway stations are located on a straight line one after another, the trains consecutively visit the stations as they move. You can assume that the stations are on the Ox axis, the i-th station is at point with coordinate xi. In such case the distance between stations i and j is calculated by a simple formula|xi - xj|.

Currently, the Ministry of Transport is choosing which stations to close and which ones to leave. Obviously, the residents of the capital won't be too enthusiastic about the innovation, so it was decided to show the best side to the people. The Ministry of Transport wants to choose such k stations that minimize the average commute time in the subway!

Assuming that the train speed is constant (it is a fixed value), the average commute time in the subway is calculated as the sum of pairwise distances between stations, divided by the number of pairs (that is ) and divided by the speed of the train.

Help the Minister of Transport to solve this difficult problem. Write a program that, given the location of the stations selects such k stations that the average commute time in the subway is minimized.

Input

The first line of the input contains integer n (3 ≤ n ≤ 3·105) — the number of the stations before the innovation. The second line contains the coordinates of the stations x1, x2, ..., xn ( - 108 ≤ xi ≤ 108). The third line contains integer k (2 ≤ k ≤ n - 1) — the number of stations after the innovation.

The station coordinates are distinct and not necessarily sorted.

Output

Print a sequence of k distinct integers t1, t2, ..., tk (1 ≤ tj ≤ n) — the numbers of the stations that should be left after the innovation in arbitrary order. Assume that the stations are numbered 1 through n in the order they are given in the input. The number of stations you print must have the minimum possible average commute time among all possible ways to choose k stations. If there are multiple such ways, you are allowed to print any of them.

Sample test(s)
input
3
1 100 101
2
output
2 3 
Note

In the sample testcase the optimal answer is to destroy the first station (with x = 1). The average commute time will be equal to 1 in this way.


题意:问你在n个点中选择m个点(要这m个点组成的每两点之和最小),输出这m个点。。

题解:这道是纯数学题。需要递推的思想。。

首先一定要排好序。。最优解一定在排好序中选择连续的m个点中的一个。。这个可以反证法证出来。。

设sum[i] = x[0]+x[1]+x[2]+x[3]+……x[i-1].

然后dp1[i]代表前i个数的每两点之和。

dp1[i] = dp1[i-1] + x[i]*i - sum[i-1];

更新到dp1[m-1]值

dp[i]代表从i开始的连续m个点的每两点之和,

dp[i] = dp[i-1] - sum[i+m-2]-sum[i-1]-x[i-1]*(m-1) + x[i+m-1]*(m) - (sum[i+m-1]-sum[i-1]);

最后循环一次更新最小值就行了。。

但是这里有一点最重要的事。。。

两个整形相乘可能溢出,就算赋值的事长整形也一样会溢出。。

如:上面公式的x[i-1]*(m-1),因为x[]和m都是在整形之内的。。

所以我们习惯定义为int,但是这样就会溢出了。。。WA

所以要将其中一个定义为__int64 这样就不会溢出了。。切记!!


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
__int64 n,m;
__int64 sum[300009];
__int64 dp1[300009],dp[300009];
struct node
{
    int x;
   int va;
}node[300009];
bool cmp(struct node a,struct node b)
{
    if(a.va<b.va)
        return true;
    else 
        return false;
}
int main()
{
    __int64 i;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d",&node[i].va);
        node[i].x = i;
    }
    scanf("%d",&m);
    sort(node,node+n,cmp);
    sum[0] = 0;
    for(i=1;i<n;i++)
    {
        sum[i] = sum[i-1]+node[i].va;
    }
        

    dp1[0] = 0;
    for(i=1;i<m;i++)
        dp1[i] = dp1[i-1] + node[i].va*i - sum[i-1];

    __int64 min = dp1[m-1];
    int start = 0;
    dp[0] = dp1[m-1];
    for(i=1;i<=n-m;i++)
    {
        __int64 var = sum[i+m-2]-sum[i-1]-node[i-1].va*(m-1);
        __int64 vv = node[i+m-1].va*(m) - (sum[i+m-1]-sum[i-1]);
        dp[i] = dp[i-1] - var + vv;
        if(min>dp[i])
        {
            min = dp[i];
            start = i;
        }
    }
    printf("%d",node[start].x+1);
    for(i=start+1;i<start+m;i++)
        printf(" %d",node[i].x+1);
    printf("\n");
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值