题目大意:有N个污点,每个污点有相应的坐标。现在有一个宽度为w的刷子,刷子可以使用k次,刷的时候,可以横刷到无穷
问最多可以刷掉多少个污点

解题思路:先离散化,预处理出每个y坐标的点,并统计一下该同一y坐标下,有多少个点
再处理一下,如果刷子的最下面刚好是该y坐标时,能刷到的所有污点数
接着就是DP了,用dp[i][j]表示刷子使用了i次,第i次刷的时候,刷子的最底部刷的是第j个y坐标的最大污点数
则dp[i][j] = dp[i - 1][k] + num[j], 其中y[k] + w < y[j],num[j]表示刷子的最下面刷的是y[j]时,能刷到的污点数

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;

struct Point{
    int x, y;
}P[N];

int n, w, k, cnt, cas = 1;
int num[N], y[N], dp[N][N];

int cmp(const Point &a, const Point &b) {
    return a.y < b.y;
}

void init() {
    scanf("%d%d%d", &n, &w, &k);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &P[i].x, &P[i].y);
    sort(P + 1, P + 1 + n, cmp);

    cnt = 1;
    y[1] = P[1].y;
    num[1] = 1;

    for (int i = 2; i <= n; i++) {
        if (P[i].y == P[i - 1].y) num[cnt]++;
        else  {
            y[++cnt] = P[i].y;
            num[cnt] = 1;
        }
    }

    for (int i = 1; i <= cnt; i++) 
        for (int j = i + 1; j <= cnt; j++) 
            if (y[i] + w >= y[j]) num[i] += num[j];
}

void solve() {
    int ans = 0;
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= cnt; i++) {
        dp[1][i] = num[i];
        ans = max(ans, dp[1][i]);
    }

    for (int i = 2; i <= k; i++)
        for (int j = 1; j <= cnt; j++) 
            for (int l = 1; l < j; l++) {
                if (y[l] + w >= y[j]) break;
                if (y[l] + w < y[j] && dp[i][j] < dp[i - 1][l] + num[j])  {
                    dp[i][j] = dp[i - 1][l] + num[j];
                    ans = max(ans, dp[i][j]);
                }
            }
    printf("Case %d: %d\n", cas++, ans);
}

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