codeforces 278Div1 B题

痛定思痛。 2021-10-23 07:23 332阅读 0赞

虚拟参赛的时候没想到是线段树,看到很多人都过了,也蛮着急的。

首先用二分+线段树的方法更新DP[i]:它表示以A[i]为结尾可以最前到哪个位置;

再用线段树计算ans[i]:它表示当前i个A元素可以最少分成多少个pieces,ans[i]=1+min(ans[j]),dp[i]-1<=j<=i-L。

over.

  1. 16 #define N 100000+5
  2. 17
  3. 18 int a[N],dp[N],Ans[N];
  4. 19 struct segment {
  5. 20 int l,r;
  6. 21 int Min,Max,ans;
  7. 22 } seg[4*N];
  8. 23
  9. 24 struct diff {
  10. 25 int Max,Min;
  11. 26 diff(int x=0,int n=0):Max(x),Min(n) {}
  12. 27 };
  13. 28
  14. 29 void build(int p,int l,int r)
  15. 30 {
  16. 31 seg[p].l=l, seg[p].r=r, seg[p].ans=-1;;
  17. 32 if (l==r) {
  18. 33 seg[p].Min = seg[p].Max = a[l];
  19. 34 return;
  20. 35 }
  21. 36 build(p<<1,l,(l+r)>>1);
  22. 37 build((p<<1)+1,((l+r)>>1)+1,r);
  23. 38
  24. 39 seg[p].Min = min(seg[p<<1].Min, seg[(p<<1)+1].Min),
  25. 40 seg[p].Max = max(seg[p<<1].Max, seg[(p<<1)+1].Max);
  26. 41 }
  27. 42
  28. 43 diff query1(int p,int l,int r)
  29. 44 {
  30. 45 if (l<=seg[p].l && seg[p].r<=r) {
  31. 46 return diff(seg[p].Max,seg[p].Min);
  32. 47 }
  33. 48
  34. 49 diff t1,t2;
  35. 50 bool f1=false, f2=false;
  36. 51 if (seg[p<<1].r>=l)
  37. 52 f1=true, t1=query1(p<<1,l,r);
  38. 53 if (seg[(p<<1)+1].l<=r)
  39. 54 f2=true, t2=query1((p<<1)+1,l,r);
  40. 55
  41. 56 if (f1) {
  42. 57 if (f2)
  43. 58 return diff(max(t1.Max,t2.Max), min(t1.Min,t2.Min));
  44. 59 else
  45. 60 return t1;
  46. 61 }
  47. 62 else
  48. 63 if (f2)
  49. 64 return t2;
  50. 65 return diff(0,0);
  51. 66 }
  52. 67
  53. 68 int query2(int p,int l,int r)
  54. 69 {
  55. 70 if (l<=seg[p].l && seg[p].r<=r) {
  56. 71 return seg[p].ans;
  57. 72 }
  58. 73
  59. 74 int t1=-1,t2=-1;
  60. 75 if (seg[p<<1].r>=l)
  61. 76 t1=query2(p<<1,l,r);
  62. 77 if (seg[(p<<1)+1].l<=r)
  63. 78 t2=query2((p<<1)+1,l,r);
  64. 79
  65. 80 if (t1==-1) {
  66. 81 return t2;
  67. 82 }
  68. 83 else {
  69. 84 if (t2==-1)
  70. 85 return t1;
  71. 86 else return min(t1,t2);
  72. 87 }
  73. 88
  74. 89 }
  75. 90
  76. 91 void add(int p,int i,int newans)
  77. 92 {
  78. 93 if (seg[p].l==seg[p].r) {
  79. 94 seg[p].ans=newans;
  80. 95 return;
  81. 96 }
  82. 97
  83. 98 if (i<=seg[p<<1].r)
  84. 99 add(p<<1,i,newans);
  85. 100 else
  86. 101 add((p<<1)+1,i,newans);
  87. 102
  88. 103 if (seg[p<<1].ans==-1) {
  89. 104 seg[p].ans = seg[(p<<1)+1].ans;
  90. 105 }
  91. 106 else {
  92. 107 if (seg[(p<<1)+1].ans==-1)
  93. 108 seg[p].ans=seg[p<<1].ans;
  94. 109 else
  95. 110 seg[p].ans=min(seg[p<<1].ans,seg[(p<<1)+1].ans);
  96. 111 }
  97. 112 }
  98. 113
  99. 114 int main()
  100. 115 {
  101. 116 //freopen("b.txt","r",stdin);
  102. 117
  103. 118 int n,s,l;
  104. 119 cin>>n>>s>>l;
  105. 120 for (int i=1;i<=n;i++) scanf("%d",&a[i]);
  106. 121 build(1,1,n);
  107. 122 for (int i=1;i<=n;i++) {
  108. 123 int L=1,R=i-1;
  109. 124 dp[i]=i;
  110. 125 while (L<=R) {
  111. 126 int mid = (L+R)>>1;
  112. 127 diff tmp = query1(1,mid,i);
  113. 128 if (tmp.Max-tmp.Min<=s) {
  114. 129 R=mid-1;
  115. 130 dp[i]=mid;
  116. 131 }
  117. 132 else {
  118. 133 L=mid+1;
  119. 134 }
  120. 135 }
  121. 136 }
  122. 137
  123. 138
  124. 139 for (int i=1;i<=n;i++) {
  125. 140 if (i<l) {
  126. 141 Ans[i]=-1;
  127. 142 continue;
  128. 143 }
  129. 144 int tmp=-1;
  130. 145 if (i-l>0 && dp[i]-1<=i-l)
  131. 146 tmp=query2(1,max(1,dp[i]-1),i-l);
  132. 147 if (dp[i]==1) tmp=0;
  133. 148
  134. 149 if (tmp==-1)
  135. 150 Ans[i]=-1;
  136. 151 else
  137. 152 Ans[i]=tmp+1, add(1,i,Ans[i]);
  138. 153 }
  139. 154 cout<<Ans[n]<<endl;
  140. 155
  141. 156 return 0;
  142. 157 }

转载于:https://www.cnblogs.com/nuaalida/p/4129407.html

发表评论

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

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

相关阅读

    相关 codeforces 278Div1 B

    虚拟参赛的时候没想到是线段树,看到很多人都过了,也蛮着急的。 首先用二分+线段树的方法更新DP\[i\]:它表示以A\[i\]为结尾可以最前到哪个位置; 再用线段树计算an