P2995 [USACO10NOV]Cow Photographs G 题解
zhiyangfan · · 题解
P2995 [USACO10NOV]Cow Photographs G
很有意思的一道题,正好初学群论,写一点从置换角度的理解。
题意
给出一个
题解
首先要知道怎么求出两个排列
即把排列
现在考虑这道题怎么做,考虑枚举最终要到达的排列,即所有
其中定义
考虑把这个置换施加到
减法定义同上。这样的话,如果能在合理时间内求出
注意到这个过程是依次相减的过程,所以我们考虑找出每次置换引起的逆序对变化。首先我们先求出
现在我们来考虑怎么求出
#include <cstdio>
#include <algorithm>
const int N = 1e5 + 10; int a[N], p[N], pos[N]; typedef long long ll;
inline void read(int& x)
{
x = 0; char ch; int f = 1;
while ((ch = getchar()) < '0' || ch > '9') f = (ch ^ '-' ? 1 : -1);
while (x = (x << 1) + (x << 3) + ch - '0', (ch = getchar()) >= '0' && ch <= '9') ;
x *= f;
}
struct BIT
{
ll c[N]; int len;
int lowbit(int x) { return x & -x; }
void add(int x, int v) { for (int i = x; i <= len; i += lowbit(i)) c[i] += v; }
ll query(int x) { ll ans = 0; for (int i = x; i; i -= lowbit(i)) ans += c[i]; return ans; }
}bit;
int main()
{
int n; read(n); bit.len = n; ll rev = 0, ans = 1e18;
for (int i = 1; i <= n; ++i)
{
read(p[i]); rev += bit.query(bit.len) - bit.query(p[i]);
bit.add(p[i], 1); pos[p[i]] = i;
}
ans = std::min(ans, rev);
for (int i = 1; i < n; ++i) rev += 1 - pos[i] + n - pos[i], ans = std::min(ans, rev);
printf("%lld\n", ans); return 0;
}