被锤爆了

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

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

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

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

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

这张图好丑啊

设\(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. Mybatis初始

    1.Mybatis 的作用 完成基本的sql语句 和 存储过程 高级的对象关系映射(ORM) 框架 封装了几乎所有的 JDBC 代码 参数的手工设置 结果集的遍历 2.Mybatis 框架的主体构成 ...

  2. MapReduce详解和WordCount模拟

    最早接触大数据,常萦绕耳边的一个词「MapReduce」.它到底是什么,能做什么,原理又是什么?且听下文讲解. 是什么 MapReduce 即是一个编程模型,又是一个计算框架,它充分采用了分治的思想, ...

  3. springboot基本注解

    声明Bean的注解: @Component组件 @Service service层 @Respository dao层 @Controller 注入Bean的注解: @Autowired Spring ...

  4. Hive & SparkSQL 比较

    Hive 在  Hadoop 集群上所有数据的访问都是通过 Java 编写的 MapReduce 作业来完成的,这些让 Java 程序员来完成没有问题. 但是对 SQL 程序员来说,写 MapRedu ...

  5. 线程协作--wait,notify:经典消费者生产者

    JDK 中关于wait,notify这两个方法的介绍: 1.wait:线程进入阻塞. synchronized (obj) { while (<condition does not hold&g ...

  6. C++多线程编程(★入门经典实例★)

    原文:http://www.cnblogs.com/codingmengmeng/p/5913068.html 多线程在编程中有相当重要的地位,我们在实际开发时或者找工作面试时总能遇到多线程的问题,对 ...

  7. 7.Java关键字和保留字

    一.概念 Java关键字(Key Word):  对Java的编译器有特殊的意义,他们用来表示一种数据类型或者表示程序的结构. 保留字(Reserve Word):即它们在Java现有版本中没有特殊含 ...

  8. xml php 解析

    JSON作为数据交换可以说已经成为了一种事实上的标准,但是前几年和它对应的xml虽然说用的越来越少,但是我感觉还是有他可以应用的地方. json更偏重于程序员来使用和解读,而xml则更适合用户来使用和 ...

  9. Tcpdump一些常用指令

    1.tcpdump安装:yum install tcpdump 2.关键字介绍 类型关键字: 指定主机 host 192.168.1.111 指定网络地址 net 202.0.0.0 指定端口 por ...

  10. 用适配器模式处理复杂的UITableView中cell的业务逻辑

    用适配器模式处理复杂的UITableView中cell的业务逻辑 适配器是用来隔离数据源对cell布局影响而使用的,cell只接受适配器的数据,而不会与外部数据源进行交互. 源码: ModelCell ...