HYSBZ 1831 逆序对
来源:互联网 发布:seo一专员 编辑:程序博客网 时间:2024/06/06 04:03
小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远。好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间。如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为一个“逆序对”。你数一数下面的数字里有多少个逆序对,你就知道Y岛离这里的距离是多少千米了。 比如说,4 2 1 3 3里面包含了5个逆序对:(4, 2), (4, 1), (4, 3), (4, 3), (2, 1)。 可惜的是,由于年代久远,这些数字里有一部分已经模糊不清了,为了方便记录,小可可用“-1”表示它们。比如说,4 2 -1 -1 3 可能原来是4 2 1 3 3,也可能是4 2 4 4 3,也可能是别的样子。 小可可希望知道,根据他们看清楚的这部分数字,能不能推断出这些数字里最少能有多少个逆序对。
Input
第一行两个正整数N和K。第二行N个整数,每个都是-1或是一个在1~K之间的数。
Output
一个正整数,即这些数字里最少的逆序对个数。
Sample Input
5 4
4 2 -1 -1 3
Sample Output
4
Hint
4 2 4 4 3中有4个逆序对。当然,也存在其它方案得到4个逆序对。
数据范围:
100%的数据中,N<=10000,K<=100。
60%的数据中,N<=100。
40%的数据中,-1出现不超过两次。
题解转自:http://blog.csdn.net/sunshinezff/article/details/51187251
首先可以证明-1位置的数一定是单调不降的.
假设相邻的两个-1的位置是(x,y)(a[x]<=a[y]);
如果交换x,y;
对1-x和y-n中的数显然没有影响.
对x-y中大于max(a[x],a[y])和小于min(a[x],a[y])的数显然也没有影响.
但是对x-y中a[x]-a[y]的数,逆序对数显然增加了.
所以交换x,y只会导致逆序对数不降.
所以-1位置的数一定是单调不降的.
然后我们就不用考虑-1之间的逆序对数了.
预处理一下lc[i][j],rc[i][j]和初始答案.
lc[i][j]表示第i个-1选j左边增加的逆序对数.
rc[i][j]表示第i个-1选j右边增加的逆序对数.
然后设f[i][j]表示前i个-1,第i个-1选j最少的逆序对数.
做一个前缀最小值转移就可以做到O(NK)了.
最后答案就是ans+f[-1的个数][k];
#include<bits/stdc++.h>const int INF = 0x3f3f3f3f;const int maxn = 5000001;const int Mod = 1e9 + 7;#define ll long long#define mem(x,y) memset(x,y,sizeof(x))using namespace std;const int N = 10010;const int M = 105;int F[N][M], a[N], p[N] = {0}, n, m, ans = 0, lc[N][M], rc[N][M], l = 0, r = 0, t = 0;int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); if (a[i] != -1) { for (int j = a[i] + 1; j <= m; j++) ans += p[j]; // 计算初始逆序数 p[a[i]]++; } else r++; } mem(p, 0); for (int i = 1; i <= n; i++) { if (a[i] == -1) { l++; lc[l][0] = t; // lc[i][j]表示第i个-1选j左边增加的逆序对数. for (int j = 1; j <= m; j++) { lc[l][j] = lc[l][j - 1] - p[j]; } } else p[a[i]]++, t++; } mem(p, 0); t = 0; for (int i = n; i >= 1; i--) { if (a[i] == -1) { rc[r][0] = 0; // rc[i][j]表示第i个-1选j右边增加的逆序对数. for (int j = 1; j <= m; j++) rc[r][j] = rc[r][j - 1] + p[j - 1]; r--; } else p[a[i]]++; } for (int i = 1; i <= l; i++) { for (int j = 1; j <= m; j++) { F[i][j] = F[i - 1][m] + lc[i][j] + rc[i][j]; // 然后设f[i][j]表示前i个-1,第i个-1选j最少的逆序对数. } for (int j = 2; j <= m; j++) { F[i][j] = min(F[i][j], F[i][j - 1]); } } cout << F[l][m] + ans ;}
- HYSBZ 1831 逆序对
- 【cdq分治】[HYSBZ/BZOJ3295]动态逆序对
- 1831: [AHOI2008]逆序对
- bzoj 1831: [AHOI2008]逆序对
- 逆序数 & 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- USACO-Section1.1 Greedy Gift Givers
- Android 基本优化(一)
- Codeforces 797E Array Queries
- Http 206 文件断点续传下载原理
- A. 这是一道简单的水题~
- HYSBZ 1831 逆序对
- linux编程之日志服务与日志编程
- 云打印服务器
- Cygwin 命令行包管理
- window对象
- 继承(五)
- MySQL Internals Manual翻译
- B. 这是数学题还是字符串题呢?
- 数据压缩 JPEG解码