zoukankan      html  css  js  c++  java
  • P4280 [AHOI2008]逆序对

    传送门

    考虑 $dp$ ,发现之前的 $-1$ 可能会产生贡献不好处理

    贪心一下发现每个位置填的数必须单调不减,所以就不用考虑之前填的数

    设 $f[i][j]$ 表示当前考虑到第 $i$ 个位置,填的数为 $j$ 时的最小代价

    那么有 $f[i][j]=f[pre][k]+val[i][j],k<=j$,$pre$ 是上一个 $-1$ 的位置,$val[i][j]$ 是在位置 $i$ 填 $j$ 时的代价,这个可以用树状数组求出

    转移只要维护一个前缀最小值即可做到 $O(1)$,记得答案要统计本身的逆序对数

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e4+7,M=207;
    int n,K,a[N];
    ll f[N][M],mi[N][M],ans;
    int t[2][N];
    inline void add(int x,int v,int p) { while(x<=K) t[p][x]+=v,x+=x&-x; }
    inline int ask(int x,int p) { int res=0; while(x) res+=t[p][x],x-=x&-x; return res; }
    int main()
    {
        n=read(),K=read();
        for(int i=1;i<=n;i++) a[i]=read();
        memset(f,0x3f,sizeof(f)); memset(mi,0x3f,sizeof(mi));
        int pre=0,tot=0;
        for(int i=1;i<=K;i++) mi[0][i]=0;
        for(int i=1;i<=n;i++) if(a[i]!=-1) add(a[i],1,1);
        for(int i=1;i<=n;i++)
        {
            if(a[i]!=-1) { ans+=(tot-ask(a[i],0)); add(a[i],1,0); add(a[i],-1,1); tot++; continue; }
            for(int j=1;j<=K;j++)
                f[i][j]=mi[pre][j] + (tot-ask(j,0)) + ask(j-1,1);
            for(int j=1;j<=K;j++)
                mi[i][j]=min(mi[i][j-1],f[i][j]);
            pre=i;
        }
        printf("%lld
    ",ans+mi[pre][K]);
        return 0;
    }
  • 相关阅读:
    linux系统安装Mysql
    makefile通用模板
    makefile常用函数
    mysqlconnector安装
    linux添加默认路由route
    .h文件与.hpp文件的区别
    ubuntu20优化开机启动
    [javascript]js原型链以及原型链继承
    webpack4.*入门笔记
    图像编程:图片大小关系
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11404996.html
Copyright © 2011-2022 走看看