题面

luogu

bzoj

题目大意:

  • 给你一个长度为\(n\)的序列,元素都在\(1-k\)之间,有些是\(-1\),让你把\(-1\)也变成\(1-k\)之间的数,使得逆序对最多,求逆序对最少是多少

  • \(n<=10000,k<=100\)

题解

结论:

填的数是不下降的

证明:

假设相邻的两个-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位置的数一定是单调不降的.

\(l[i][j]\)表示前\(i\)个数有多少大于\(j\)的数

\(r[i][j]\)表示后\(i\)个数有多少小于\(j\)的数

我们把-1位置弄出来\(dp\)

\(f[i][j]\)表示第\(i\)位填\(j\),逆序对个数最少是多少

\(b[i]\)表示第i个空在原序列的位置

假设\(i\)位填\(t\)

\(f[i][t] = min(f[i-1][z]+l[b[i]][t]+r[b[i]][t])\)

这样复杂度是\(O(n*k^2)\)

  • 注意还要加上没填数时的逆序对

可以发现\(f[i-1][z]\) 可以用一个前缀最小来优化

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N= 10010;
int cnt, l[N][110], r[N][110], a[N], b[N];
LL f[N][110], g[N][110];
int main() {
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
int n, k; read(n); read(k);
for (int i = 1; i <= n; i++) {
read(a[i]);
if (a[i] == -1) b[++cnt] = i;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= k; j++) {
l[i][j] = l[i-1][j];
if (a[i] > j) l[i][j]++;
}
for (int i = n; i >= 1; i--)
for (int j = 1; j <= k; j++) {
r[i][j] = r[i+1][j];
if (a[i] < j && a[i] != -1) r[i][j]++;
}
for (int i = 1; i <= cnt; i++) g[i][0] = 1ll << 60;
for (int i = 1; i <= cnt; i++)
for (int j = 1; j <= k; j++) {
f[i][j] = g[i-1][j]+l[b[i]][j]+r[b[i]][j];
g[i][j] = min(g[i][j-1], f[i][j]);
}
LL ans = 1ll << 60;
for (int i = 1; i <= k; i++) ans = min(ans, f[cnt][i]);
for (int i = 1; i <= n; i++) ans += l[i][a[i]];
printf("%lld\n", ans);
return 0;
}

洛谷 P4280 bzoj1786 [AHOI2008]逆序对(dp)的更多相关文章

  1. bzoj1831: [AHOI2008]逆序对(DP+双精bzoj1786)

    1831: [AHOI2008]逆序对 Description 小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之 ...

  2. 【洛谷 P2513】 [HAOI2009]逆序对数列(DP)

    题目链接 这种求方案数的题一般都是\(dp\)吧. 注意到范围里\(k\)和\(n\)的范围一样大,\(k\)是完全可以更大的,到\(n\)的平方级别,所以这暗示了我们要把\(k\)写到状态里. \( ...

  3. 洛谷 P1393 P3157 动态逆序对

    嘛,好久没碰CDQ分治了,做道题练练手. 时间倒流——把删数改为加数. 对于每个被删的,我的想法是拆成询问和add,后来发现一个足矣. 我本来准备对每个删的数都求一遍整体逆序对,后来发现无论如何都不可 ...

  4. 洛谷 P3157 [CQOI2011]动态逆序对 解题报告

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列\(A\),它的逆序对数定义为满足\(i<j\),且\(A_i>A_j\)的数对\((i,j)\)的个数.给\(1\)到\(n ...

  5. 洛谷 P3157 [CQOI2011]动态逆序对(树套树)

    题面 luogu 题解 树套树(树状数组套动态开点线段树) 静态使用树状数组求逆序对就不多说了 用线段树代替树状数组,外面套树状数组统计每个点逆序对数量 设 \(t1[i]\)为\(i\)前面有多少个 ...

  6. 洛谷P1966 火柴排队(逆序对)

    题意 题目链接 Sol 不算很难的一道题 首先要保证权值最小,不难想到一种贪心策略,即把两个序列中rank相同的数放到同一个位置 证明也比较trivial.假设\(A\)中有两个元素\(a, b\), ...

  7. 洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治

    题目:https://www.luogu.org/problemnew/show/3157 题解: 1.对于静态的逆序对可以用树状数组做 2.我们为了方便可以把删除当成增加,可以化动为静 3.找到三维 ...

  8. 洛谷【P1908】逆序对

    题目传送门:https://www.luogu.org/problemnew/show/P1908 所谓逆序对,就是序列中\(a[i]>a[j]\)且\(i<j\)的有序对. 所以我们在归 ...

  9. 洛谷P3157 [CQOI2011]动态逆序对

    题目大意: 给定\(1\)到\(n\)的一个排列,按照给定顺序依次删除\(m\)个元素,计算每个元素删除之前整个序列的逆序对数量 基本套路:删边变加边 那么我们不就是求满足\(pos_i<pos ...

随机推荐

  1. 【bzoj1614】[Usaco2007 Jan]Telephone Lines架设电话线

    题目描述 Farmer John打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务.于是,FJ必须为此向电信公司支付一定的费用.     FJ的农场周围分布着N(1 <= N < ...

  2. Linux查看操作系统版本的几种方式

    Linux查看操作系统版本的几种方式: 1.uname -a 2.lsb_release -a 3.cat /etc/issue 4.cat /proc/version 5.cat /etc/redh ...

  3. 2.sql分类

    SQL DML 和 DDL 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL). SQL (结构化查询语言)是用于执行查询的语法.但是 SQL 语言也包含用于更新.插 ...

  4. 235D Graph Game

    传送门 题目大意 https://www.luogu.org/problemnew/show/CF235D 分析 我们先考虑它是树的情况 我们设$event(x,y)$表示删除点x是y与x联通这件事对 ...

  5. UOJ#46. 【清华集训2014】玄学

    传送门 分析 清华集训真的不是人做的啊嘤嘤嘤 我们可以考虑按操作时间把每个操作存进线段树里 如果现在点x正好使一个整块区间的右端点则更新代表这个区间的点 我们不难发现一个区间会因为不同的操作被分成若干 ...

  6. Luogu 3350 [ZJOI2016]旅行者

    BZOJ 4456 听若干个大佬讲过$n$遍终于写掉了. 我把时限基本上跑满了2333…… 分治 + 最短路. 首先我们去分治这个矩形格子,找到一条长边把它对半切,对切开的边上的每一个点跑一遍最短路然 ...

  7. linux查看进程开始时间

    ps -eo pid,lstart|grep [pid] 命令解释: -e Select all processes. -o,o Specify user-defined format. pid a ...

  8. 编写高质量代码改善C#程序的157个建议——建议29:区别LINQ查询中的IEnumerable<T>和IQueryable<T>

    建议29:区别LINQ查询中的IEnumerable<T>和IQueryable<T> LINQ查询一共提供了两类扩展方法,在System.Linq命名空间下,有两个静态类:E ...

  9. Linux:SSH免密码登录

    1.使用包管理器安装openssh: 本人的系统是Arch Linux,因此安装命令为:sudo pacman -S openssh 2.使用ssh-keygen命令创建公钥: #ssh-keygen ...

  10. attachEvent 与 addEventListener 的监听

    说到 attachEvent 与 addEventListener 的事件必然会提到  浏览器的判断,因为attachEvent只适用于于IE 先来看看常用的浏览器的判断 //判断浏览器类型 if(n ...