bzoj1786: [Ahoi2008]Pair 配对

来源:互联网 发布:绝对伏特加 知乎 编辑:程序博客网 时间:2024/05/22 07:50

传送门
首先要YY出一个性质:在-1处天的数单调不减。
很显然,大的数放前面,小的数放后面逆序对增多。
然后f[i][j]表示前i个-1,第i个-1上填的数字是j的最优解。
转移自己YY以下九可以了。

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cstdlib>#define ll long longusing namespace std;int a[10005],b[10005],big[10005][105],sma[10005][105],g[105],f[105];int n,l,mi,ans,tot;int main(){    scanf("%d%d",&n,&l);    for (int i=1;i<=n;i++){        scanf("%d",&a[i]);        if (a[i]==-1) b[++tot]=i;    }    for (int i=2;i<=n;i++){        memcpy(big[i],big[i-1],sizeof(big[i-1]));        if (a[i-1]!=-1)            for (int j=1;j<a[i-1];j++) big[i][j]++;    }    for (int i=n-1;i>=1;i--){        memcpy(sma[i],sma[i+1],sizeof(sma[i+1]));        if (a[i+1]!=-1)            for (int j=a[i+1]+1;j<=l;j++) sma[i][j]++;    }    for (int i=1;i<=n;i++) if (a[i]!=-1) ans+=sma[i][a[i]];    for (int i=1;i<=l;i++) g[i]=big[b[1]][i]+sma[b[1]][i];    for (int i=2;i<=tot;i++){        for (int j=2;j<=l;j++) g[j]=min(g[j],g[j-1]);        for (int j=1;j<=l;j++) f[j]=g[j]+big[b[i]][j]+sma[b[i]][j];        memcpy(g,f,sizeof(f));    }    mi=g[1];    for (int i=2;i<=l;i++) mi=min(mi,g[i]);    printf("%d",ans+mi);}