zoukankan      html  css  js  c++  java
  • BZOJ 1786 配对(DP)

    如果我们直接令dp[i][j]为前i个位置第i个位置填j所产生的逆序对的最少数。这样是不满足无后效性的。

    但是如果发现对于两个-1,如果前面的-1填的数要大于后面的-1填的数。容易证明把他们两交换结果不会变差。

    所以对于所有的-1,填的数一定是一个非递减的。

    现在我们考虑每个位置对答案的贡献。显然数字位和数字位的逆序对数可以预处理一次算出来。

    而-1位和-1位的逆序对数是0,剩下的就是数字位和-1位的逆序对数。

    考虑dp[i][j]为前i个-1位 第i个-1位填j时产生的逆序对的最少数。这样是没有后效的。有dp[i][j]=min(dp[i][k])+f[j]+t[j].(k<=j).

    f[j]表示第i个-1位填j和前面的数字位产生的逆序对总数。t[j]表示第i个-1位填j和后面的数字位产生的逆序对总数。这两个数组可以在一次O(nk)的预处理完成。

    dp的复杂度是O(nk).所以总复杂度是O(nk).

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi 3.1415926535
    # define eps 1e-9
    # define MOD 100000007
    # define INF 1000000000
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=10005;
    //Code begin...
    
    int a[N], res, f[N][105], t[N][105], dp[N][105], mi[N][105];
    
    int main ()
    {
        int n, k, ans=INF;
        scanf("%d%d",&n,&k);
        FOR(i,1,n) scanf("%d",a+i);
        FOR(i,1,k) FOR(j,1,n) {
            if (j>1&&a[j-1]==-1) f[j][i]=f[j-1][i];
            else if (j>1&&a[j-1]!=-1) f[j][i]=f[j-1][i]+(i<a[j-1]);
        }
        FOR(i,1,k) for (int j=n; j>=1; --j) {
            if (j<n&&a[j+1]==-1) t[j][i]=t[j+1][i];
            else if (j<n&&a[j+1]!=-1) t[j][i]=t[j+1][i]+(i>a[j+1]);
        }
        int pos=0;
        FOR(i,1,n) {
            if (a[i]!=-1) {res+=f[i][a[i]]; continue;}
            ++pos;
            FOR(j,1,k) {
                dp[pos][j]=mi[pos-1][j]+f[i][j]+t[i][j];
                if (j>1) mi[pos][j]=min(dp[pos][j],mi[pos][j-1]);
                else mi[pos][j]=dp[pos][j];
            }
        }
        FOR(j,1,k) ans=min(ans,dp[pos][j]);
        printf("%d
    ",ans+res);
        return 0;
    }
    View Code
  • 相关阅读:
    蓝桥杯基础 算法训练 图形显示 (简单模拟,坑)
    越喜欢村上春树,就越懂得生活
    HTML 基础 之 列表标签 () 学习笔记
    HTML 基础 之 段落标签() 学习笔记
    《Norwegain Wood》—— The Beatles
    蓝桥杯基础 算法训练 前缀表达式 (基础语法)
    Python3 使用 urllib 包访问Web网站
    蓝桥杯 算法提高 队列操作 (STL基本操作)
    蓝桥杯 算法提高 11-1 实现strcmp函数 (C语言实现,指针实现)
    蓝桥杯基础 算法训练 矩阵乘法 (模板题)
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6605461.html
Copyright © 2011-2022 走看看