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

这两道题是一样的。

可以发现,-1变成的数是单调不降。

记录下原有的逆序对个数。

预处理出每个点取每个值所产生的逆序对个数,然后dp转移。

#include<cstring>
#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
#include<algorithm>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define low(x) (x&(-x))
#define maxn 10050
#define inf 2000000000
#define mm 1000000007
using namespace std;
int f[maxn][105],a[maxn],t[maxn],pos[maxn],c[maxn][105];
int now,n,k,cnt,ans;
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch==‘-‘) f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-‘0‘; ch=getchar();}
    return x*f;
}
void add(int x,int y){
    while (x<=k){
        t[x]=t[x]+y;
        x+=low(x);
    }
}
int ask(int x){
    int ans=0;
    while (x){
        ans+=t[x];
        x-=low(x);
    }
    return ans;
}
int main(){
    n=read(); k=read();
    rep(i,1,n){
        a[i]=read();
        if (a[i]!=-1){
            ans+=ask(k)-ask(a[i]); add(a[i],1);
        }
        else {
            pos[++cnt]=i;
            rep(j,1,k) c[i][j]+=ask(k)-ask(j);
        }
    }
    clr(t,0);
    down(i,n,1){
        if (a[i]!=-1) add(a[i],1);
        else {
            rep(j,1,k) c[i][j]+=ask(j-1);
        }
    }
    rep(i,1,cnt) rep(j,0,k) f[i][j]=inf;
    rep(i,1,cnt){
        int now=pos[i];
        rep(j,1,k) f[i][j]=min(f[i][j-1],f[i-1][j]+c[now][j]);
    }
    printf("%d\n",f[cnt][k]+ans);
    return 0;
} 
时间: 2024-10-15 16:39:37

BZOJ1786: [Ahoi2008]Pair 配对/1831: [AHOI2008]逆序对的相关文章

bzoj1786: [Ahoi2008]Pair 配对&amp;&amp;1831: [AHOI2008]逆序对

一个自以为很对的东西,我们往-1放的数肯定是不增的. 然后就预处理一下,假如i这个位置放j会多多少逆序对. DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以过就不管了. 注意树状数组的时候getsum是a[i]-1,相同是不算逆序对的 #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorit

【BZOJ1786】[Ahoi2008]Pair 配对 DP

[BZOJ1786][Ahoi2008]Pair 配对 Description Input Output Sample Input 5 4 4 2 -1 -1 3 Sample Output 4 题解:结论!!!为了使逆序对最少,我们在-1位置填入的数一定是单调不减的.(可以用反证法证明,很简单.) 所以DP,我们用f[i][j]表示枚举到第i个数,上一个在-1位置填入的数是j个最少逆序对个数.然后转移也很简单~ #include <cstdio> #include <cstring&g

BZOJ 1786: [Ahoi2008]Pair 配对 题解

[原题] 1786: [Ahoi2008]Pair 配对 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 399  Solved: 241 [Submit][Status] Description Input Output Sample Input 5 4 4 2 -1 -1 3 Sample Output 4 HINT Source Day1 [分析]一看到就感觉有思路,好像-1的格子有什么规律.于是开始YY. 简单的脑补:设A,B,C三个点,A

BZOJ1786 [Ahoi2008]Pair 配对 动态规划 逆序对

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1786 题意概括 给出长度为n的数列,只会出现1~k这些正整数.现在有些数写成了-1,这些-1可以变成任何数. 求把这些-1变成1~k中的正整数之后,最少的逆序对个数为多少. 题解 我们可以判断,这些-1中写的数字一定是单调不降的. 为什么?我们把答案序列的所有-1位抽出来,如果答案序列中有一组是逆序的,那么交换他们,一定可以保证小的那个换到大的那个的位置的时候,它左右产生的逆序对数一定比大的原先

算法-逆序对(归并排序)

我觉得每次博客时,开头的话语是最难写的,这次就不写了,但是要鼓励自己好好学习! 题意: 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个 逆序对.给你一个数组,求出这个数组中逆序对的总数. 概括:如果a[i] > a[j] 且 i < j, a[i] 和 a[j] 构成一个逆序对. 样例: 序列 [2, 4, 1, 3, 5] 中,有 3 个逆序对 (2, 1), (4, 1), (4, 3),则返回 3 这题理解起来不是很难的,但是麻烦的地方就是时间复杂度.如果用常规的

bzoj1831【AHOI2008】逆序对

1831: [AHOI2008]逆序对 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 485  Solved: 341 [Submit][Status][Discuss] Description 小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间.如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为一个"逆序对".你数一数下面的数字里有多少个

动态规划 BZOJ1831 [AHOI2008]逆序对

1831: [AHOI2008]逆序对 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 660  Solved: 469[Submit][Status][Discuss] Description 小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间.如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为一个"逆序对".你数一数下面的数字里有多少个逆序

BZOJ1831: [AHOI2008]逆序对

1831: [AHOI2008]逆序对 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 341  Solved: 226[Submit][Status] Description 小可可和小卡卡想到Y岛上旅游,但是他们不知道Y岛有多远.好在,他们找到一本古老的书,上面是这样说的: 下面是N个正整数,每个都在1~K之间.如果有两个数A和B,A在B左边且A大于B,我们就称这两个数为一个“逆序对”.你数一数下面的数字里有多少个逆序对,你就知道Y岛离这里的距离

[AHOI2008] 逆序对

link 我们可以很容易的推断出$-1$是单调不降的,若$i>j$且$a_i$与$a_j$都没有填数,若填完之后$a_i>a_j$或者$a_i<a_j$,则对答案产生影响的只在$[i,j]$之间,则$a_i<a_j$对答案产生的贡献更小,则其实每个不同位置的$-1$其实是互不影响的,所以就可以用$dp$实现 设$dp(i,j)$表示这是从右往左数第$i$个$-1$,这里填j的最小逆序对数(这里的逆序对是只与$-1$有关的,其他的单算) 则$dp(i,j)=min(dp(i-1,p)