B1786 [Ahoi2008]Pair 配对 逆序对+dp
这个题有点意思,一开始没想到用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
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 */
只想找一个不会伤害我的人