AOJ 0271: Izua Dictionary

解説

文字列をsとして愚直にシミュレーションしていくと、sを適当に入れ替えたときのi番目(1 <= i <= n)の文字の位置を求めるのに、i番目までに使った文字が影響される。よって最初にBITで[1, n]に1を加えておき、s[i]の場所ごとにiを0にしていくことで、sum(i)でi番目の文字の位置を求めることができる。(日本語難しすぎ)
割とゴリ押しな感じあふれてる。

ソースコード

めっちゃ汚い…

typedef long long i64;
const i64 MOD = 1000000007;
const int MAX_N = 100002;

struct BinaryIndexedTree {
	int data[MAX_N];

	BinaryIndexedTree() {
		memset(data, 0, sizeof data);
	}

	// [1, n]
	i64 sum(i64 i) {
		i64 ret = 0;
		for(; i > 0; i -= i & -i) {
			ret += data[i];
		}
		return ret;
	}

	void add(i64 i, i64 x) {
		for(; i < MAX_N; i += i & -i) {
			data[i] += x;
		}
	}
};

int main() {
	int pair[MAX_N];
	i64 ans;
	i64 fact[MAX_N];
	
	fact[0] = 1;
	for(int i = 1; i < MAX_N; i++) {
		fact[i] = i * fact[i - 1];
		fact[i] %= MOD;
	}

	int n, r;
	while(cin >> n, n) {
		cin >> r;

		ans = 0;
		BinaryIndexedTree b;

		for(int i = 0; i < MAX_N; i++) {
			b.add(i + 1, 1);
			pair[i] = i;
		}

		for(int i = 0, a, b; i < r; i++) {
			cin >> a >> b;
			swap(pair[a-1], pair[b-1]);
		}

		for(int i = 0; i < n; i++) {
			i64 x = b.sum(pair[i] + 1) - 1;
			b.add(pair[i] + 1, -1);
			ans += x * fact[n - i - 1];
			ans %= MOD;
		}

		cout << ans << endl;
	}
}