kmjp's blog

競技プログラミング参加記です

Indeedなう(本選B) : E - Line up!

Dより簡単じゃないですかね…。
http://indeednow-finalb-open.contest.atcoder.jp/tasks/indeednow_2015_finalb_e

問題

N要素の数列H[i]がある。
隣接2要素をスワップして、数列を昇順にしたい。
ただし隣接要素をスワップするには、2要素のうち小さい方の値だけコストがかかる。

条件を満たす最小コストを求めよ。

解法

H[i]に同じ要素が複数あると条件を満たせない。
以後、H[i]がすべて異なる場合を考える。

H[i]に対し、j<iかつH[j]>H[i]となるjの個数を求め、その個数とH[i]を掛けたものがH[i]をそれより大きな数字とスワップするコストとなる。
よって各iに対し上記jの個数を求めればよい。

これはH[i]を座標圧縮すれば、あとはSegTreeなりBITで解ける。

int N;
ll H[101000];
map<int,int> M;

template<class V, int ME> class BIT {
public:
	V bit[1<<ME],val[1<<ME];
	V total(int e) {V s=0;e++;while(e) s+=bit[e-1],e-=e&-e; return s;}
	V add(int e,V v) { val[e++]+=v; while(e<=1<<ME) bit[e-1]+=v,e+=e&-e;}
};
BIT<int,20> bt;
ll ret;

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(i,N) {
		cin>>H[i];
		if(M[H[i]]>0) {
			cout<<-1<<endl;
			return;
		}
		M[H[i]]=1;
	}
	x=0;
	ITR(it,M) it->second=++x;
	FOR(i,N) {
		ret += H[i]*(i-bt.total(M[H[i]]));
		bt.add(M[H[i]],1);
	}
	cout<<ret<<endl;
}

まとめ

わりとすんなり。