#include #include #include using namespace std; static const int SIZE = 1024; static const double MAX = 1e10; //i番目からj番目まで(inclusive) double memoMin[SIZE][SIZE]; //最小値 double memoMax[SIZE][SIZE]; //最大値 double memoError[SIZE][SIZE]; //区間二乗誤差 double memoAnswer[SIZE][SIZE]; //解 int main() { int N, M, L; while (cin >> N >> M >> L && N && M && L){ double values[SIZE]; for (int i = 0; i < N; ++i){ cin >> values[i]; } fill_n((double*)memoMin, SIZE * SIZE, MAX); fill_n((double*)memoMax, SIZE * SIZE, MAX); fill_n((double*)memoError, SIZE * SIZE, MAX); fill_n((double*)memoAnswer, SIZE * SIZE, MAX); //i番目からj番目までの範囲のサンプルの最小値、最大値を求める O(N^2) for (int from = 0; from < N; ++from){ double minValue = values[from]; double maxValue = values[from]; for (int to = from + 1; to < N; ++to){ minValue = min(minValue, values[to]); maxValue = max(maxValue, values[to]); memoMin[from][to] = minValue; memoMax[from][to] = maxValue; } } //i番目からj番目までの範囲のサンプルの二乗量子化誤差の和をDPで求める O(N^3) for (int from = 0; from < N; ++from){ for (int to = from + 1; to < N; ++to){ const double minValue = memoMin[from][to]; const double maxValue = memoMax[from][to]; const double stepSize = (maxValue - minValue) / ((1 << L) - 1); double sum2 = 0; for (int current = from; current <= to; ++current){ const double currentValue = values[current]; const double estimatedValue = (int)((currentValue - minValue + stepSize * 0.5) / stepSize) * stepSize + minValue; const double error = currentValue - estimatedValue; sum2 += error * error; } memoError[from][to] = sum2; } } //i番目までにj個の時分割フレームを使用した時の二乗量子化誤差の和をDPで求める O(N^3) for (int to = 1; to < N; ++to){ memoAnswer[1][to] = memoError[0][to]; } for (int numberOfFrames = 2; numberOfFrames <= M; ++numberOfFrames){ for (int from = 1; from < N; ++from){ for (int to = from + 1; to < N; ++to){ double& answer = memoAnswer[numberOfFrames][to]; answer = min(answer, memoAnswer[numberOfFrames - 1][from - 1] + memoError[from][to]); } } } printf("%.20lf\n", memoAnswer[M][N - 1]); } }