1. 程式人生 > >B1786 [Ahoi2008]Pair 配對 逆序對+dp

B1786 [Ahoi2008]Pair 配對 逆序對+dp

int 逆序 枚舉 main getch algo clean urn putchar

這個題有點意思,一開始沒想到用dp,沒啥思路,後來看題解才恍然大悟:k才1~100,直接枚舉每個-1點的k取值進行dp就行了。先預處理出來sz[i][j] i左邊的比j大的數,lz[i][j] i右邊比j小的數。然後就沒啥了。

題幹:

Description

技術分享圖片

Input

技術分享圖片

Output

技術分享圖片

Sample Input

5 4
4 2 -1 -1 3

Sample Output

4 代碼:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include
<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template
<class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < 0 || c > 9) if(c == -) op = 1; x = c - 0; while(c = getchar(), c >= 0 && c <= 9) x = x * 10 + c - 0; if(op) x = -x; } template <class
T> void write(T x) { if(x < 0) putchar(-), x = -x; if(x >= 10) write(x / 10); putchar(0 + x % 10); } int n,m,tot = 0; int a[10020],num[10020]; int lz[10050][105]; int sz[10020][105]; int dp[10020][105]; int k; int main() { read(n);read(k); duke(i,1,n) { read(a[i]); if(a[i] == -1) num[++tot] = i; } duke(i,1,n) { duke(j,1,k) { if(a[i - 1] > j) sz[i][j] = sz[i - 1][j] + 1; else sz[i][j] = sz[i - 1][j]; } } lv(i,n - 1,1) { duke(j,1,k) { if(a[i + 1] < j && a[i + 1] != -1) lz[i][j] = lz[i + 1][j] + 1; else lz[i][j] = lz[i + 1][j]; } } duke(i,1,n) { duke(j,1,k) { if(a[i] != -1) { dp[i][j] = dp[i - 1][j]; continue; } else { dp[i][j] = INF; duke(l,1,k) { dp[i][j] = min(dp[i - 1][l] + lz[i][j] + sz[i][j],dp[i][j]); } } } } int ans = INF; duke(i,1,k) { ans = min(ans,dp[n][i]); } duke(i,1,n) { if(a[i] != -1) { ans += sz[i][a[i]]; } } printf("%d\n",ans); return 0; } /* 5 4 4 2 -1 -1 3 */

B1786 [Ahoi2008]Pair 配對 逆序對+dp