Problem:
G - Derangement / 完全順列

Story

Dのひとは順列に関する研究をしている。あるときDのひとは、"完全順列 (Derangement)"という順列のクラスを見つけた。「完全な順列とかなんかかっこいい！！！しかもDからはじまる！！！」と廚二病をこじらせたDのひとは、与えられた順列をすべて完全順列に書き換えてしまおうと考えた。

Problem

長さnの順列p = (p_1 p_2 ... p_n)が与えられる。i番目の要素とj番目の要素を入れ替える操作には(p_i+p_j) \times |i-j|のコストを要する。このとき、上記の入れ替え操作のみを用いてpを完全順列にするために必要な最小のコストを求めよ。

ただし、順列qが完全順列であるとは、1 \leq i \leq nについて、q_i \neq iが成り立つことを言う。たとえば、(5 3 1 2 4)は完全順列であるが、(3 2 5 4 1)は4番目の数が4なので完全順列ではない。

Input

入力は以下の形式からなる。

n
p_1 p_2 ... p_n

1行目は順列の長さnを表す整数1つからなる。 2行目はn個の整数からなり、i番目の整数は順列pのi番目の要素を表す。それぞれは空白1文字で区切られている。

制約:

2 \leq n \leq 100

1 \leq p_i \leq n, i \neq j ⇔ p_i \neq p_j

Output

pを完全順列に並び替えるための最小コストを1行に出力せよ。行の最後では必ず改行を行うこと。

Sample Input 1

5
1 2 3 5 4

Sample Output 1

7

1と2を入れ替えた後、1と3を入れ替えると、(2 3 1 5 4)となり完全順列である。

Sample Input 2

5
5 3 1 2 4

Sample Output 2

0

始めから完全順列である。

Sample Input 3

10
1 3 4 5 6 2 7 8 9 10

Sample Output 3

38

Solution in C (judge verdict: Accepted)

// AOJ 2581 Derangement
// 2018.3.9 bal4u

#include <stdio.h>
#include <string.h>

#define QMAX 10000
typedef struct { int t, s; } QUE;
QUE que[QMAX]; int qsize;

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

void min_heapify(int i)
{
	int l, r, min;
	QUE qt;

	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].t < que[i].t) min = l; else min = i;
	if (r < qsize && que[r].t < que[min].t) min = r;
	if (min != i) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		min_heapify(min);
	}
}

void deq()
{
	que[0] = que[--qsize];
	min_heapify(0);
}

void enq(int s, int t)
{
	int i, min;
	QUE qt;

	i = qsize++;
	que[i].s = s, que[i].t = t;
	while (i > 0 && que[min = PARENT(i)].t > que[i].t) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		i = min;
	}
}

#define INF 0x10101010
#define MAX 205
typedef struct { int to, rev; int cap, cost; } EDGE;
EDGE edge[MAX][MAX]; int hi[MAX];
int V;				// 頂点数
int potential[MAX], dist[MAX], prevv[MAX], preve[MAX];

void add_edge(int from, int to, int cap, int cost)
{
	int f, t;
	EDGE *ep;

	f = hi[from]++, t = hi[to]++;
	ep = &edge[from][f], ep->to = to, ep->cap = cap, ep->cost = cost, ep->rev = t; 
	ep = &edge[to][t], ep->to = from, ep->cap = 0, ep->cost = -cost, ep->rev = f;
}

int minCostFlow(int S, int T, int F)
{
	int i, v, nv, t, nt, ret;
	EDGE *ep;

	ret = 0;
//	memset(potential, 0, V << 2);
  
	while (F > 0) {
		memset(dist, INF, V << 2);
		qsize = 0;
		enq(S, 0), dist[S] = 0;
		while (qsize) {
			v = que[0].s, t = que[0].t, deq();
			if (dist[v] < t) continue;
			for (i = 0; i < hi[v]; i++) {
				ep = &edge[v][i];
				if (ep->cap <= 0) continue;
				nv = ep->to;
				nt = t + ep->cost - potential[nv] + potential[v];
				if(dist[nv] > nt) {
					dist[nv] = nt;
					prevv[nv] = v, preve[nv] = i;
					enq(nv, nt);
				}
			}
		}
		if (dist[T] == INF) return -1;
		for (v = 0; v < V; v++) potential[v] += dist[v];

		t = F;
		for (v = T; v != S; v = prevv[v]) {
			ep = &edge[prevv[v]][preve[v]];
			if (t > ep->cap) t = ep->cap;
		}
		F -= t;

		ret += t * potential[T];
		for (v = T; v != S; v = prevv[v]) {
			ep = &edge[prevv[v]][preve[v]];
			ep->cap -= t;
			edge[v][ep->rev].cap += t;
		}
	}
	return ret;
}

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int c = getchar_unlocked();
	do n = 10*n + (c & 0xf), c = getchar_unlocked();
	while (c >= '0');
	return n;
}

int p[102];

int main()
{
	int n, i, j;
	int source, sink;

	n = in();
	source = n << 1, sink = source+1, V = sink+1;

	for (i = 0; i < n; i++) p[i] = in();

	for (i = 0; i < n; i++) {
		add_edge(source, i, 1, 0);

		for (j = 0; j < i; j++) if (p[i] != j+1)
			add_edge(i, n+j, 1, (i-j)*p[i]);
		for ( ; j < n; j++) if (p[i] != j+1)
			add_edge(i, n+j, 1, (j-i)*p[i]);

		add_edge(n+i, sink, 1, 0);
	}

	printf("%d\n", minCostFlow(source, sink, n));
	return 0;
}