bzoj 1786 && bzoj 1831: [Ahoi2008]Pair 配对(DP)

来源:互联网 发布:报名系统源码 编辑:程序博客网 时间:2024/05/22 15:34

1786: [Ahoi2008]Pair 配对

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 899  Solved: 591
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

5 4
4 2 -1 -1 3

Sample Output

4


一个很好的结论是:

填入的数一定要不严格递增,因为如果填入的数中存在逆序对,那么交换这两个数一定会使答案更优

这样就可以dp了

步骤:

①预处理sum[i][x]为第i个数如果为x那么包含x的逆序对为sum[i][x]个

②dp[i][x]表示第i个数填上x最少有dp[i][x]个逆序对

上面两个数组都可以O(nk)处理出来所有情况

复杂度O(nk)

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int a[10005], s1[10005][105], s2[10005][105], dp[10005][105];int main(void){int n, k, i, j, last, ans, now;scanf("%d%d", &n, &k);for(i=1;i<=n;i++)scanf("%d", &a[i]);for(i=1;i<=k;i++){for(j=1;j<=n;j++){s1[j][i] = s1[j-1][i];if(a[j]>i)s1[j][i] += 1;}for(j=n;j>=1;j--){s2[j][i] = s2[j+1][i];if(a[j]<i && a[j]!=-1)s2[j][i] += 1;}for(j=1;j<=n;j++)s1[j][i] += s2[j][i];}ans = last = 0;memset(dp, 62, sizeof(dp));for(i=1;i<=n;i++){if(a[i]!=-1){ans += s1[i][a[i]];continue;}now = 2e9;for(j=1;j<=k;j++){if(last==0)dp[i][j] = s1[i][j];else{now = min(now, dp[last][j]);dp[i][j] = now+s1[i][j];}}last = i;}now = 2e9;for(i=1;i<=k;i++)now = min(now, dp[last][i]);if(last==0)printf("%d\n", ans/2);elseprintf("%d\n", ans/2+now);return 0;}/*5 44 2 -1 4 3*/


原创粉丝点击