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

問題

数直線(x軸)上に並んだn個の地下鉄の駅があります。各駅の座標はx[i]であらわされます。
悲しいことにこの地下鉄は財政難なので、駅をk個まで減らさないといけなくなりました。

減らし方の戦略として、kC2個の任意の2駅間距離の総和が最少になるものを選びたいです。
そうなるような駅の番号を出力してください。

制約

3≦n≦300000
2≦k≦n-1
abs(x[i])≦10^8


解法

k個の連続した(間に選ばれてない駅を挟まない)駅の選び方が最適そうなので、
とりあえず座標値で駅をソートしましょう。

したらばn-k+1個の選択肢となり、それぞれの場合の全点間距離を計算すればよさそうですが、
最小値自体ではなく、最小値を満たす選択肢を見つけられればよいので、
その差分だけを求めればよいです。

左からi個目の駅をl[i]とし、
l[i]からl[i+k-1]までのk個の駅の全点間距離をf(i,k)とすると、
f(i+1,k)-f(i,k)=
(l[i+1]からl[i+k-1]までのk-1個の点とl[i+k]との距離の総和)-
(l[i+1]からl[i+k-1]までのk-1個の点とl[i]との距離の総和)

で求められます。i番目からj番目までの座標値の総和は、1番目からj番目までの座標値の総和をO(n)で前計算しておくことでO(1)で求められます。
というわけでO(n)で最小値をとる区間を見つけられます。
この問題のように「ソートしてから考えるけど、最後にもともとの順番を出力する」ような問題は
(座標値、index)のペアでソートすると楽です。

プログラム

#include<iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include<string>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<sstream>
#include<algorithm>
#include<map>
#include<complex>
#include<ctime>
#include<set>
using namespace std;


#define li			long long int
#define rep(i,to)	for(li i=0;i<((li)(to));i++)
#define repp(i,start,to)	for(li i=(li)(start);i<((li)(to));i++)
#define pb			push_back
#define sz(v)		((li)(v).size())
#define bgn(v)		((v).begin())
#define eend(v)		((v).end())
#define allof(v)	(v).begin(), (v).end()
#define dodp(v,n)		memset(v,(li)n,sizeof(v))
#define bit(n)		(1ll<<(li)(n))
#define mp(a,b)		make_pair(a,b)
#define rin	rep(i,n)
#define EPS 1e-10
#define ETOL 1e-8
#define MOD 100000000
#define F first
#define S second
#define p2(a,b)		cout<<a<<"\t"<<b<<endl
#define p3(a,b,c)		cout<<a<<"\t"<<b<<"\t"<<c<<endl

vector<pair<li,li> > x;
li sum[300300];

int main(){
	li n,k;
	li tmp;
	cin>>n;
	rin{
		cin>>tmp;
		x.pb(mp(tmp,i+1));
	}
	cin>>k;

	sort(allof(x));
	sum[0]=0;
	rin{
		sum[i+1]=sum[i]+x[i].F;
	}

	li mi=0;
	li idx=0;
	li now=0;

	repp(i,1,n-k+1){
		li overlap=sum[i+k-1]-sum[i];
		now-=(overlap-x[i-1].F*(k-1));
		now+=(x[i+k-1].F*(k-1)-overlap);
		if(mi>now){
			mi=now;
			idx=i;
		}
	}

	rep(i,k){
		cout<<x[idx+i].S<<" ";
	}puts("");

	return 0;
}