被锤爆了

被这个题搞得自闭了一上午,觉得自己没什么前途了

我又没有看出来这个题的一个非常重要的性质

我们填进去的数一定是单调不降的

首先如果填进去的数并不是单调不降的,那么填进去本身就会产生一些逆序对,感性理解好像是单调不降更优,这里还是严谨证明一下吧

考虑一下树状数组求逆序对的过程,显然就是求出每一个数前面有多少个比它大的数

这张图好丑啊

设\(A<B\),\(x\)表示那段绿色区间里大于\(A\)的数,\(y\)表示绿色区间里大于\(B\)的数,\(a\)表示蓝色区间里大于\(A\)的数,\(b\)表示蓝色区间里大于\(B\)的数

这个时候我们如果用树状数组来统计一下答案的话,\(A,B\)的贡献就是\(x+y+b\)

如果交换一下\(A\)和\(B\)的位置,那么这个时候答案就会变成\(x+a+y+1\)

非常显然的是\(b<=a\),所以可以得出\(x+y+b<x+a+y+1\),所以不交换更优

之后有了这个性质,我们就可以做一个\(dp\)了,设\(dp[i][j]\)表示填到了\(i\)位置,最靠后的一个\(-1\)位置填了\(j\)这个时候的最小逆序对是多少

就可以一边树状数组一边\(dp\)了

复杂度\(O(nklogk)\)

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define lowbit(x) ((x)&(-x))
#define re register
#define maxn 100005
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
char c=getchar();
int x=0,r=1;
while(c<'0'||c>'9')
{
if(c=='-') r=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x*r;
}
LL c[105];
int n,m;
LL ans;
LL dp[maxn][101];
LL mx[101];
int pre[maxn];
int a[maxn];
int beh[maxn][101];
inline void add(int x)
{
for(re int i=x;i<=m;i+=lowbit(i)) c[i]++;
}
inline LL ask(int x)
{
LL now=0;
for(re int i=x;i;i-=lowbit(i)) now+=c[i];
return now;
}
int main()
{
int cnt=0;
n=read(),m=read();
for(re int i=1;i<=n;i++)
{
a[i]=read();
if(a[i]==-1&&!cnt) cnt=i;
pre[i]=pre[i-1]+(a[i]==-1);
}
if(!cnt) cnt=n+1;
for(re int i=1;i<cnt;i++)
{
ans+=ask(m)-ask(a[i]);
add(a[i]);
}
if(cnt==n+1)
{
std::cout<<ans;
return 0;
}
for(re int i=n;i;i--)
{
for(re int j=1;j<=m;j++)
beh[i][j]=beh[i+1][j];
if(a[i]==-1) continue;
for(re int j=a[i];j<=m;j++) beh[i][j]++;
}
memset(dp,20,sizeof(dp));
for(re int i=1;i<=m;i++)
dp[cnt][i]=ans+ask(m)-ask(i)+beh[cnt][i-1];
memset(mx,20,sizeof(mx));
for(re int j=1;j<=m;j++)
mx[j]=min(mx[j-1],dp[cnt][j]);
for(re int i=cnt+1;i<=n;i++)
{
if(a[i]!=-1)
{
LL now=ask(m)-ask(a[i]);
for(re int j=1;j<=m;j++)
dp[i][j]=now+dp[i-1][j];
add(a[i]);
}
else
{
for(re int j=1;j<=m;j++)
{
LL now=ask(m)-ask(j);
dp[i][j]=mx[j]+now+beh[i][j-1];
}
}
memset(mx,20,sizeof(mx));
for(re int j=1;j<=m;j++)
mx[j]=min(mx[j-1],dp[i][j]);
}
LL Ans=0x7ffffffff;
for(re int i=1;i<=m;i++)
Ans=min(Ans,dp[n][i]);
std::cout<<Ans;
return 0;
}

【[AHOI2008]逆序对】的更多相关文章

  1. BZOJ1831: [AHOI2008]逆序对

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

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

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

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

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

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

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

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

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

  6. [AHOI2008] 逆序对

    link 我们可以很容易的推断出$-1$是单调不降的,若$i>j$且$a_i$与$a_j$都没有填数,若填完之后$a_i>a_j$或者$a_i<a_j$,则对答案产生影响的只在$[i ...

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

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

  8. [AHOI2008]逆序对(dp)

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

  9. BZOJ 1831: [AHOI2008]逆序对

    题目大意: 给出一个序列,有几个位置上的数字任意.求最小的逆序对数. 题解: 自己决定放置的数一定是单调不降的.不然把任意两个交换一下就能证明一定会增加逆序对. 然后就可以DP了,f[i][j]表示第 ...

随机推荐

  1. Linux 服务器 MySql的安装和网站的发布

    Linux安装MySql,并配置能通过自己的电脑连接服务器的数据库 昨天安装的MySql,今天上午配置MySql能使用本机连接服务器数据库,服务器时DigitalOcean的,提供了很全面很专业的文档 ...

  2. SVG 旋转图形实例

    本实例展示如何在SVG中画出一个正方形并使之旋转.运行结果如下图所示: 在文本框中输入时间间隔,单位是毫秒.点击Start按钮,蓝色方块就会开始转动,每个时间间隔变化一度.变换的角度在下面的Angle ...

  3. Bundle传递数据,Handler更新UI

    Bundle主要用于传递数据:它保存的数据,是以key-value(键值对)的形式存在的. Bundle经常使用在Activity之间或者线程间传递数据,传递的数据可以是boolean.byte.in ...

  4. [C语言] 数据结构-预备知识指针

    所有的伟大源于一个勇敢的开始 数据结构预备知识 指针 1.指针:是C语言的灵魂,指针=地址 地址:内存单元的编号 指针变量:存放内存单元地址的变量 int *p;//p是指针变量,int *表示该p变 ...

  5. 十二、异步工具Timer

    一.简介 JDK提供一种异步线程工具Timer类,你可以利用这个类做延迟任务.周期性任务等. JDK文档:http://tool.oschina.net/uploads/apidocs/jdk-zh/ ...

  6. hashmap的一些基础原理

    本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...

  7. Java CountDownLatch解析(上)

    写在前面的话 最近一直在边工作边学习分布式的东西,看到了构建Java中间件的基础知识,里面有提到Java多线程并发的工具类,例如ReentrantLock.CyclicBarrier.CountDow ...

  8. Freebsd10.3 Nginx多版本PHP

    服务器上需要使用多个php版本,费了好几天劲,终于有所收获.记录如下: 1.下载php-5.5.37.tar.bz2. 2.tar zvxf  php-5.5.37.tar.bz2 -C /usr/l ...

  9. js中常用的算法排序

    在工作中都会经常用到的一些基础算法,可以很快解决问题.这些都是在工作中总结的,希望可以帮助到大家. 一.数组乱序 arr.sort(function randomsort(a, b) { return ...

  10. MongoDB 排序文档

    sort() 方法 要在 MongoDB 中的文档进行排序,需要使用sort()方法. sort() 方法接受一个文档,其中包含的字段列表连同他们的排序顺序. 要指定排序顺序1和-1. 1用于升序排列 ...