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

一个自以为很对的东西,我们往-1放的数肯定是不增的。

然后就预处理一下,假如i这个位置放j会多多少逆序对。

DP一下,我的复杂度应该是O(n*m^2)的,然而你随便搞都能省掉一个m吧,我算了算好像可以过就不管了。

注意树状数组的时候getsum是a[i]-1,相同是不算逆序对的

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int s[110];
int lowbit(int x){return x&-x;}
void change(int x,int k)
{
    while(x<=100)
    {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=s[x];
        x-=lowbit(x);
    }
    return ret;
}

//-----------bit-求逆序对-------------------

int a[11000];
int c[11000][110];

int f[11000][110];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int _know=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        if(a[i]!=-1)
            _know++, change(a[i],1);
        else
            for(int j=1;j<=m;j++)c[i][j]=_know-getsum(j);
    }
    memset(s,0,sizeof(s));
    int ans=0;
    for(int i=n;i>=1;i--)
    {
        if(a[i]!=-1)
        {
            ans+=getsum(a[i]-1);
            change(a[i],1);
        }
        else
            for(int j=1;j<=m;j++)c[i][j]+=getsum(j-1);
    }

    //--------init-------------

    memset(f,63,sizeof(f));f[1][1]=0;
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(a[i]!=-1)
            {
                f[i][j]=f[i-1][j];
            }
            else
            {
                for(int k=1;k<=j;k++)
                    f[i][j]=min(f[i][j],f[i-1][k]+c[i][j]);
            }
        }
    }
    int ss=(1<<30);
    for(int j=1;j<=m;j++)ss=min(ss,f[n][j]);
    printf("%d\n",ans+ss);
    return 0;
}

原文地址:https://www.cnblogs.com/AKCqhzdy/p/9040519.html

时间: 2024-10-06 23:40:29

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

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++)

【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)