题目大意:有n种珠宝,每件珠宝有必须要买的数量ai和单价pi,c种珠宝的单价递增。如果买了某种珠宝,需要额外付一次10*pi的费用,同时允许用等量的高价珠宝代替等量的的低价珠宝,问至少要花多少钱,才能达到要求

解题思路:设 dp[i]为买前i种珠宝需要花费的最小代价
得转移方程dp[i] = dp[j] + (sum[i] - sum[j] + 10) * val[i]
sum[i]指前i中珠宝的数量和
假设k > j,且k点比j点更优
则 dp[j] + (sum[i] - sum[j] + 10 ) * val[i] >= dp[k] + (sum[i] - sum[k] + 10) * val[i]

化简可得val[i] >= (dp[k] - dp[j]) / (sum[k] - sum[j])
因为价格递增,所以得到优化方程

#include <cstdio>
#include <cstring>

const int N = 110;
int sum[N], val[N], dp[N], que[N];
int n;

void init() {
    dp[0] = sum[0] = 0;

    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &sum[i], &val[i]);
        sum[i] += sum[i - 1];
    }
}

int getUp(int j, int k) {
    return dp[j] - dp[k];
}

int getDown(int j, int k) {
    return sum[j] - sum[k];
}

int getDp(int i, int j) {
    return dp[j] + (sum[i] - sum[j] + 10) * val[i];
}

void solve(){ 
    int head, tail;
    head = tail = 0;
    que[tail++] = 0;

    for (int i = 1; i <= n; i++) {
        while (head + 1 < tail && getUp(que[head + 1], que[head]) <= getDown(que[head + 1], que[head]) * val[i]) 
            head++;
        dp[i] = getDp(i, que[head]);

        while (head + 1 < tail && getUp(i, que[tail - 1]) * getDown(que[tail - 1], que[tail - 2]) <= getUp(que[tail - 1], que[tail - 2]) * getDown(i, que[tail - 1]))
            tail--;
        que[tail++] = i;
    }
    printf("%d\n", dp[n]);
}

int main() {
    int test;
    scanf("%d", &test);
    while (test--) {
        init();
        solve();
    }
    return 0;
}