HDU 6249 Alice’s Stamps

 

題目連接php

 

題目大意:c++

說有$m$個區間,要求選出不超過$k$個區間,使這些區間覆蓋的長度最長,問最長長度是多少。spa

題解:blog

全部區間按$R$從小到大排序以後能夠進行$dp$。排序

$dp[i][j]$表示:拿了小於等於$i$個區間,最後一個以座標小於等於$j$爲結尾的最長覆蓋長度get

假設第$x$個區間做爲結尾,那麼要分兩種狀況來考慮:it

1.能夠是以前的結尾小於第$x$個區間的左端點,這種狀況很好解決。class

2.也能夠是以前區間的結尾在第$x$個區間內部。sort

第二種狀況的話:di

不容許在區間內部進行枚舉點,不然時間複雜度炸了,能夠發現要求的是相似於$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;
}
相關文章
相關標籤/搜索