码迷,mamicode.com
首页 > 其他好文 > 详细

[AHOI2008] 逆序对

时间:2018-11-05 11:13:09      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:线段树   www   ++   图片   pen   memset   ide   org   int   

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)+在第i个-1左面不是-1的对此数新产生的逆序对数+此数填后对右面产生的贡献) (j \leq p)$

我们可以用线段树维护逆序对,时间复杂度:$O(n\times k^2)$

技术分享图片
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read(){
    int f=1,ans=0;char c;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();}
    return f*ans;
}
int n,k,a[10001],cnt[10001],ans[40014];
void add(int k,int l,int r,int x,int y){
    if(x>y) return ;
    if(x<=l&&r<=y){ans[k]++;return;}
    int mid=l+r>>1;
    if(x<=mid) add(k<<1,l,mid,x,y);
    if(mid<y) add(k<<1|1,mid+1,r,x,y);
    ans[k]=ans[k<<1]+ans[k<<1|1];
    return;
}
int query(int k,int l,int r,int x,int y){
    if(x>y) return 0;
    if(x<=l&&r<=y) return ans[k];
    int mid=l+r>>1,res=0;
    if(x<=mid) res+=query(k<<1,l,mid,x,y);
    if(mid<y) res+=query(k<<1|1,mid+1,r,x,y);
    return res;
}
int cost[10001][101],sum,dp[10001][101],tot,minn,inf=2<<30-1;
int main(){
    minn=inf;
    memset(dp,127/3,sizeof(dp));
    n=read(),k=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        if(a[i]==-1)
            cnt[++cnt[0]]=i;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            cost[i][j]=cost[i-1][j];
            if(j<=a[i]) cost[i][j]++;
        }
    }
    for(int i=1;i<=k;i++) dp[0][i]=0;
    for(int i=n;i>=1;i--){
        if(a[i]!=-1){
            sum+=query(1,1,k,1,a[i]-1);
            add(1,1,k,a[i],a[i]);
        }else{
            tot++;
            for(int j=1;j<=k;j++){
                for(int p=j;p<=k;p++){
                    dp[tot][j]=min(dp[tot-1][p]+query(1,1,k,1,j-1)+cost[i][j+1],dp[tot][j]);
                    if(tot==cnt[0]) minn=min(minn,dp[tot][j]);
                }
            }
        }
    }
    if(minn==inf) cout<<sum;
    else cout<<sum+minn;
}
View Code

 

[AHOI2008] 逆序对

标签:线段树   www   ++   图片   pen   memset   ide   org   int   

原文地址:https://www.cnblogs.com/si-rui-yang/p/9907506.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!