1831: [AHOI2008]逆序对

Description

小可可和小卡卡想到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出现不超过两次。


题解:
想了有好一段时间,第一反应是dp没错。
定义f[i][j]表示第i个-1填j的逆序对数最小。
然后...对于状态转移一脸懵逼qwq
又想了好久,发现其实按顺序从前往后填的话,每次填的数都一定是单调递增的(不严格)
哎~美滋滋~
到底为什么呢?
在一个序列当中,对于x,y两个数(x>y),位置为i和j(i>j)
如果我们将x和y调换位置的话会出现以下几种情况:

1、1~i-1和j+1~n中的数与x,y构成的逆序对数不变。

2、i+1~j-1中大于x的数或者小于y的数与x,y构成的逆序对数不变。

3、i+1~j-1中在y~x范围内的数与x,y构成的逆序对数减少。

那么看到这里我们就可以发现,如果我们在i和j这两个位置分别填了x,y这两个数,那么只有x<y时得到的解才是最优的!

自然而然-转移方程:f[i][j]=s[i-1][j]+hf[i][j];

s[i][j]表示的就是f[i][1]~f[i][j]解的最小值

hf[i][j]表示的就是在第i个位置填入j之后所产生的逆需对(这个很明显就可以预处理嘛~)

但是我们需要把hf数组分成两个部分:

q[11000][110];//表示第i个位置填了j之后,1~i有多少个逆序对——顺推
h[11000][110];//表示第i个位置填了j之后,i~n有多少个逆序对(对于后面不是-1的数来说)——逆推

说到这里就可以了,AC~~~

PS:双倍经验!!!bzoj1786


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read()
{
int f=,x=;char ch;
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return f*x;
}
int n,k,last;
int a[],b[];
int f[][];//表示第i个-1填j的逆序对数最小(1<=j<=k && 保证序列中填的一定是一个上升序列所得的解才为最优)
int q[][];//表示第i个位置填了j之后,1~i有多少个逆序对——顺推
int h[][];//表示第i个位置填了j之后,i~n有多少个逆序对(对于后面不是-1的数来说)——逆推
int s[][];//表示f[i][1]~f[i][j]解的最小值
//方程:f[i][j]=s[i-1][j]+hf[i][j];
int main()
{
//freopen("1831.in","r",stdin);
//freopen("1831.out","w",stdout);
n=read(),k=read();int sum=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]==-)b[++sum]=i;
} //预处理: //前
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
{
int ss=;
if(a[i]>j)ss=;
q[i][j]=q[i-][j]+ss;
} //后
for(int i=n;i>=;i--)
for(int j=;j<=k;j++)
{
int ss=;
if(a[i]!=- && a[i]<j)ss=;
h[i][j]=h[i+][j]+ss;
} memset(f,,sizeof(f));
for(int i=;i<=sum;i++)
{
f[i][]=f[i-][]+q[b[i]][]+h[b[i]][];
s[i][]=f[i][];
for(int j=;j<=k;j++)
{
f[i][j]=s[i-][j]+q[b[i]][j]+h[b[i]][j];
s[i][j]=min(s[i][j-],f[i][j]);
}
} int ans=;
for(int i=;i<=k;i++)ans=min(ans,f[sum][i]);
for(int i=;i<=n;i++)if(a[i]!=-)ans+=q[i][a[i]];
printf("%d\n",ans);
return ;
}

bzoj1831: [AHOI2008]逆序对(DP+双精bzoj1786)的更多相关文章

  1. BZOJ1831: [AHOI2008]逆序对

    1831: [AHOI2008]逆序对 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 341  Solved: 226[Submit][Status] ...

  2. 洛谷 P4280 bzoj1786 [AHOI2008]逆序对(dp)

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

  3. 【BZOJ1831】[AHOI2008]逆序对(动态规划)

    [BZOJ1831][AHOI2008]逆序对(动态规划) 题面 BZOJ 洛谷 题解 显然填入的数拎出来是不降的. 那么就可以直接大力\(dp\). 设\(f[i][j]\)表示当前填到了\(i\) ...

  4. BZOJ1786: [Ahoi2008]Pair 配对/1831: [AHOI2008]逆序对

    这两道题是一样的. 可以发现,-1变成的数是单调不降. 记录下原有的逆序对个数. 预处理出每个点取每个值所产生的逆序对个数,然后dp转移. #include<cstring> #inclu ...

  5. [AHOI2008]逆序对(dp)

    小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间.如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为 ...

  6. bzoj1786: [Ahoi2008]Pair 配对&&1831: [AHOI2008]逆序对

    一个自以为很对的东西,我们往-1放的数肯定是不增的. 然后就预处理一下,假如i这个位置放j会多多少逆序对. DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以 ...

  7. bzoj1831 逆序对 (dp+树状数组)

    注意到,所有的-1应该是一个不降的序列,否则不会更优那就先求出来不是-1的的逆序对个数,然后设f[i][j]表示第i个-1放成j的前i个-1带来的最小逆序对数量这个可以树状数组来求 #include& ...

  8. 【BZOJ】1831: [AHOI2008]逆序对

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1831 考虑$-1$的位置上填写的数字一定是不降的. 令${f[i][j]}$表示$DP$到 ...

  9. 【[AHOI2008]逆序对】

    被锤爆了 被这个题搞得自闭了一上午,觉得自己没什么前途了 我又没有看出来这个题的一个非常重要的性质 我们填进去的数一定是单调不降的 首先如果填进去的数并不是单调不降的,那么填进去本身就会产生一些逆序对 ...

随机推荐

  1. ASP.NET-post、get的区别

    post.get的区别 1.get通过把参数加在浏览器的地址栏中提交(最大2K),用post可以进行文件的提交: 2.使用post提交的页面在点击[刷新]按钮的时候浏览器一般会提示"是否重新 ...

  2. 洛谷 P3133 [USACO16JAN]无线电联系Radio Contact

    P3133 [USACO16JAN]无线电联系Radio Contact 题目描述 Farmer John has lost his favorite cow bell, and Bessie the ...

  3. POSIX 线程编程(一)简介

    简介 在共享内存的多处理器结构中,可以用线程来实现并行.对于UNIX系统, IEEE POSIX 1003.1c标准规定了C语言线程编程接口的标准.这份标准的实现就是POSIX threads, 或者 ...

  4. JAVA设计模式之【迭代器模式】

    迭代器模式 聚合类,聚合对象 电视机遥控器,迭代器,遍历局和对象中的成员 灵活新增遍历方法 将负责遍历数据的方法提取出来,封装到专门的类中,实现数据存储和数据遍历分离.这就是迭代器模式. 灵活性,可扩 ...

  5. GIT GUI简易教程

    GIT GUI简易教程 前言 之前一直想一篇这样的东西,因为最初接触时,我也认真看了廖雪峰的教程,但是似乎我觉得讲得有点多,而且还是会给我带来很多多余且重复的操作负担,所以我希望能压缩一下它在我工作中 ...

  6. httputil用http获取请求的工具类

    package com.xiaocan.demo.util; import java.io.IOException; import java.io.InputStream; import java.u ...

  7. sql/plus无法显示数据库问题

    登录PL/SQL Developer 这里省略Oracle数据库和PL/SQL Developer的安装步骤,注意在安装PL/SQL Developer软件时,不要安装在Program Files ( ...

  8. GPG加密windows中使用

    在Windows系统使用Gpg4win进行加密解密 2015-06-15 by u014076884 GPG,又称为GnuPG,全称是Gnu Private Guard,即GNU隐私卫士.GPG是以P ...

  9. IOS系统设置页面跳转

    目录: 跳转 iOS10- 版本跳转url转 iOS10+ 版本跳转url转 跳转符 跳转到系统设置界面代码: // 自己应用的设置界面:url = UIApplicationOpenSettings ...

  10. HTML的常用标签属性及使用时需注意的一些细节

    前言 本篇随笔的主要是复习一下常用的一些HTML(Hyper Text Markup Language)标签及其属性,并总结一些使用过程中需要注意的一些细节,本篇提及的常用标签主要有: iframe标 ...