Gym - 101201H

野性酷女 2022-05-14 12:51 207阅读 0赞

70

题意:有k个区间,用他们填满1~n,不允许重叠,问留下的空隙最少是多少

思路:可以从两方面考虑,第一个是正面考虑,转移方程dp[i]=min(dp[j]+l[i]-r[j]+1) (r[j]<l[i])

这样的话将方程移项 dp[i]-l[i]-1=min(dp[j]-r[j]),所以用树状数组维护dp[j]-r[j]的最小值就可以了

为了计算方便,添加一个终点区间(n+1,n+1)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int N=2e5+10;
  5. const ll INF=0x3f3f3f3f3f3f3f3f;
  6. ll n, val[N], s[N], dp[N];
  7. int k, up;
  8. struct inter{
  9. ll l, r;
  10. }in[N];
  11. bool cmp(inter a, inter b){
  12. return a.r<b.r || a.r==b.r&&a.l<b.l;
  13. }
  14. void upd(int x, ll v){
  15. for(; x<=up; x+=x&-x)
  16. s[x]=min(s[x], v);
  17. }
  18. ll query(int x){
  19. ll ret=INF;
  20. for(; x>0; x-=x&-x)
  21. ret=min(s[x], ret);
  22. return ret;
  23. }
  24. int main(){
  25. scanf("%I64d%d", &n, &k);
  26. for(int i=1; i<=k; i++){
  27. scanf("%lld%lld", &in[i].l, &in[i].r);
  28. val[i]=in[i].r;
  29. }
  30. k++;
  31. in[k].l=n+1, in[k].r=n+1;
  32. val[k]=0; val[k+1]=n+1;
  33. sort(in+1, in+1+k, cmp);
  34. sort(val+1, val+2+k);
  35. up=unique(val+1, val+2+k)-val-1;
  36. /* for(int i=1; i<=up; i++) printf("%lld ", val[i]);
  37. puts("");
  38. */
  39. for(int i=1; i<=k; i++){
  40. ll p=in[i].l-1;
  41. p=upper_bound(val+1, val+1+up, p)-val-1;
  42. ll mn=query(p);
  43. dp[i]=mn+in[i].l-1;
  44. // printf("%lld %lld\n", mn, dp[i]);
  45. p=lower_bound(val+1, val+1+up, in[i].r)-val;
  46. upd(p, dp[i]-in[i].r);
  47. //printf("%I64d ", dp[i]);
  48. }
  49. printf("%lld\n", dp[k]);
  50. return 0;
  51. }

第二个方面是从反面考虑,这样会是问题非常简单,dp[i]是前i个区间覆盖和的最大值

dp[i]=max(dp[j])+len[i]

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. typedef pair<ll, ll> pll;
  5. const ll N=2e5+10;
  6. const ll INF=0x3f3f3f3f3f3f3f3f;
  7. pll p[N];
  8. ll dp[N];
  9. int main(){
  10. ll n, k;
  11. scanf("%lld%lld", &n, &k);
  12. ll a, b;
  13. for(int i=1; i<=k; i++){
  14. scanf("%lld%lld", &a, &b);
  15. p[i]=pll(b,a);
  16. }
  17. sort(p+1, p+1+k);
  18. for(int i=1; i<=k; i++){
  19. int pr=lower_bound(p+1, p+1+k, pll(p[i].second, 0))-p-1;
  20. ll tmp;
  21. if(pr==0)
  22. tmp=p[i].first-p[i].second+1;
  23. else
  24. tmp=dp[pr]+p[i].first-p[i].second+1;
  25. dp[i]=max(tmp, dp[i-1]);
  26. // cout<<pr<<" "<<dp[i]<<endl;
  27. }
  28. printf("%lld\n", n-dp[k]);
  29. return 0;
  30. }

发表评论

表情:
评论列表 (有 0 条评论,207人围观)

还没有评论,来说两句吧...

相关阅读

    相关 gym224647B

    gym224647B 题意: > 在二维平面中·选出一个面积最小的三角形,输出这个三角形面积的两倍。 解法: > 首先,最优解一定在相邻最近的三个点...

    相关 GYM 100685 K

    乱搞题 统计每一个不是magic word的单词,然后每个make\_pair 然后按照公式计算答案。 因为这里是乱序的统计make\_pair的情况,所以如果相邻

    相关 Gym - 101201H

    ![70][] 题意:有k个区间,用他们填满1~n,不允许重叠,问留下的空隙最少是多少 思路:可以从两方面考虑,第一个是正面考虑,转移方程dp\[i\]=min(dp\[j