hdu 5497 Inversion(高效)
2015-10-11 22:40
393 查看
题目链接:hdu 5497 Inversion
解题思路
先处理出每个位置与前后面形成的逆序对数L[i],R[i]。然后维护一段长度为M的区间,从起始为值为1到N-M,维护删除该段区间会破坏多少逆序对数,保留最大值,用总的减去即可。代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5 + 5; typedef long long ll; #define lowbit(x) ((x)&(-x)) struct Fenw { int n, f[maxn]; void init(int n) { this->n = n; memset(f, 0, sizeof(f)); } void add(int x, int v) { while (x <= n) { f[x] += v; x += lowbit(x); } } int sum(int x) { int ret = 0; while (x) { ret += f[x]; x -= lowbit(x); } return ret; } int query (int l, int r) { return sum(r) - sum(l-1); } }P, S; int N, M, L[maxn], R[maxn], A[maxn]; ll G; void init () { G = 0; scanf("%d%d", &N, &M); for (int i = 0; i < N; i++) scanf("%d", &A[i]); P.init(N+1); for (int i = 0; i < N; i++) { L[i] = P.query(A[i] + 1, N + 1); P.add(A[i], 1); G = G + L[i]; } P.init(N+1); for (int i = N-1; i >= 0; i--) { R[i] = P.query(1, A[i] - 1); P.add(A[i], 1); } } ll solve () { P.init(N+1); S.init(N+1); ll sum = 0; for (int i = 0; i < M; i++) { sum += R[i]; S.add(A[i], 1); } ll ret = sum; for (int i = M; i < N; i++) { sum += R[i] - R[i-M] - L[i-M]; S.add(A[i-M], -1); S.add(A[i], 1); sum += S.query(1, A[i-M]-1) + P.query(A[i]+1, N+1); P.add(A[i-M], 1); ret = max(ret, sum); } //printf("%lld %lld\n", ret, G); return G - ret; } int main () { int cas; scanf("%d", &cas); while (cas--) { init (); printf("%lld\n", solve()); } return 0; }
相关文章推荐
- 计算器
- hihoCoder 1242 MX Loves Game
- [iOS 开发的正确姿势] 之一 代码风格篇
- LintCode : 背包问题 II
- 全面理解HTTP
- GTD中回顾闭环
- Part 99 Lambda expression in c#
- EasyUI - Panel 面板控件
- Provisioning Services 7.6 入门到精通系列之十一:批量导入目标设备
- C 习题和解析(继承和派生-01)
- 采购管理中,包括哪些内容?
- poco c++ 框架: Util 读取配置文件
- 1、Struts2 的简单配置
- mysql的索引问题
- 面试题32:从1到n整数中1出现的次数
- ATM
- div水平居中
- 求2进制中的1的个数
- 黑马程序员——JavaSE之对单例枚举和反射的看法一
- 20135223何伟钦—信息安全系统设计基础第五周学习总结