基础不扎实,写得时候被"f[i] = new int[K + 1];“这行代码坑了半天,写成"f[i] = new int[K + 1]{INT_MAX};”,还没有反应过来,哈哈。。。
/*
* 有一个长度为n的序列,每个数都是1~K中的整数。
* 现在有一些位置的数被遮住了,用-1表示。
* 你可以往这些位置填1~K中的数,使得整个序列的逆序对数最小,
* 求最小的逆序对数。
* N<=10000,K<=100
* 逆序对数:i<j,a[i]>a[j]。(有关逆序对数的性质及相关证明在同济线性代数第一章有)
*
* 首先确保填进去数字的区间是不产生逆序对的,也就是说,填进去的数字是不严格单调增的。
* 证明:假设被遮住的区间是[i,j],记为L,区间[1,i-1]记为M,区间[j+1,n]记为N,a<b。
1、在i处填上a,在j处填上b。(i+1~j-1这一部分没有填,所以先不看)
* 填上a产生的新的逆序对记为C(a)=M(a)+L(a)+N(a)=M(a)+N(a),
* 填上b产生的新的逆序对记为C(b)=M(b)+L(b)+N(b)=M(b)+N(b)。
* 区间L中并没有产生逆序对,所以L(a)=L(b)=0。
* 2、在i处填上b,在j处填上a。
* 填上a产生的新的逆序对记为C(a)=M(a)+L(a)+N(a),
* 填上b产生的新的逆序对记为C(b)=M(b)+L(b)+N(b)。
* 显然情况2比情况1多产生了L(a)+L(b)的逆序对。
* 3、如果a=b,同1
* 所以填进去的数字是不严格单调增的
*
* 创建二维数组f[i][j]表示填到了第i个数,第i个数填了j(1<=j<=K)后所产生的逆序对数C(j)
* C(j)中包含了[1,i-1]中比j大的数和[i+1,n]中比j小的数,分别记作M(j)和N(j)。
* 依次与前面已经填好的i-1个数产生的逆序对f[i-1][k](1<=k<=K),可以得到f[i-1][k]+M(j)+N(j);
* 所以f[i][j]=min(f[i-1][k]+M(j)+N(j))。
* 最终结果应该是min(f[Length][j]),Length为要填充区间的长度,1<=j<=K
*/
#include<iostream>
#include<vector>
#include<iomanip>
using namespace std;
const vector<int> A = {
4,3,2,-1,-1,1,6};
const int Length = count(A.begin(), A.end(), -1);//求出要填充的区间长度
const int Begin = find(A.begin(), A.end(), -1) - A.begin();//需要填充数字的起始下标
const int End = Begin + Length - 1;//需要填充数字的终止下标
int single_inverse(int num,int k);//求出数组中插入第k个元素产生的新的逆序数
void