HDU 6249 Alice’s Stamps

 

题目链接

 

题目大意:

说有$m$个区间,要求选出不超过$k$个区间,使这些区间覆盖的长度最长,问最长长度是多少。

题解:

所有区间按$R$从小到大排序之后可以进行$dp$。

$dp[i][j]$表示:拿了小于等于$i$个区间,最后一个以坐标小于等于$j$为结尾的最长覆盖长度

假设第$x$个区间作为结尾,那么要分两种情况来考虑:

1.可以是之前的结尾小于第$x$个区间的左端点,这种情况很好解决。

2.也可以是之前区间的结尾在第$x$个区间内部。

第二种情况的话:

不允许在区间内部进行枚举点,否则时间复杂度炸了,可以发现要求的是类似于$dp[j] + i - j$格式的最大值,也就是$i$加上区间上$dp[j]-j$的最大值,因此可以用ST表计算区间最大值。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2100;
int T, n, m, K;
struct X {
  int L, R;
  int x;
}s[maxn];
int dp[maxn][maxn];
int t[maxn * 4];
int rmq[maxn][15];

bool cmp(const X&a, const X&b) {
  return a.R < b.R;
}

void ST(int num) {
  for (int i = 1; i <= n; i++)
    rmq[i][0] = dp[num][i] - i;
  for (int j = 1; (1 << j) <= n; j++) {
    for (int i = 1; i + (1 << j) - 1 <= n; i++) {
      rmq[i][j] = max(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]);
    }
  }
}

int RMQ(int l, int r) {
  int k = 0;
  while ((1 << (k + 1)) <= r - l + 1) k++;
  return max(rmq[l][k], rmq[r - (1 << k) + 1][k]);
}

int main() {
  scanf("%d", &T);
  int cas = 1;
  while(T --) {
    scanf("%d%d%d", &n, &m, &K);
    for(int i = 1; i <= m; i ++) {
      scanf("%d%d", &s[i].L, &s[i].R);
      s[i].x = s[i].R - s[i].L + 1;
    }
    sort(s + 1, s + 1 + m, cmp);
    /*
     dp[i][j], 拿了 <= i 个,最后一个以坐标 <= j 为结尾
     */
    int ans = 0;
    ST(0);
    for(int i = 1; i <= K; i ++) {
      int now = 1;
      while(now <= m && s[now].R < i) now ++;
      for(int j = i; j <= n; j ++) {
        dp[i][j] = 0;
        while(now <= m && s[now].R == j) {
          dp[i][j] = max(dp[i][j],
                            s[now].x + dp[i - 1][s[now].L - 1]);
          dp[i][j] = max(dp[i][j],
                            RMQ(s[now].L, s[now].R) + j);
          now ++;
        }
        dp[i][j] = max(dp[i][j - 1], dp[i][j]);
        ans = max(ans, dp[i][j]);
        if(ans == n) break;
      }
      if(ans == n) break;
      ST(i);
    }
    printf("Case #%d: %d\n", cas ++, ans);
  }
  return 0;
}

 

posted @ 2018-02-08 11:41  Fighting_Heart  阅读(284)  评论(0编辑  收藏  举报