我是靠谱客的博主 多情向日葵,这篇文章主要介绍Codeforces 1185 C2. Exam in BerSU (hard version)(权值线段树 + 二分 查询前 K 大的和),现在分享给大家,希望可以做个参考。
题目:题目链接
题意:给定一个长度为 n 的数组 a 和 一个数 M,问对于每一个 i ,在区间 [1,i - 1] 删除最少的数,使得[1,i - 1]中剩下的数的和 + a[i] <= M,问最少删除多少个数。
思路:显然要删除最少个数,肯定是从大到小进行删除,关键就是怎么确定从大到小的数的和,这就是需要解决的问题。那么我是用权值线段树来进行维护的如整个区间第 k 大一样,然后查询的时候求前 k 大的数的和,然后对于每一个 i ,直接二分删除多少个数即可。
AC代码:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89#include<bits/stdc++.h> #define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl #define pii pair<int,int> #define clr(a,b) memset((a),b,sizeof(a)) #define rep(i,a,b) for(int i = a;i < b;i ++) #define pb push_back #define MP make_pair #define LL long long #define ull unsigned LL #define ls i << 1 #define rs (i << 1) + 1 #define INT(t) int t; scanf("%d",&t) using namespace std; const int maxn = 2e5 + 10; int sum[maxn << 2]; int C[maxn << 2]; int t[maxn],K[maxn]; void update(int l,int r,int p,int i){ if(l == r){ ++ sum[i]; C[i] += K[p]; return ; } int mid = (l + r) >> 1; if(p <= mid) update(l,mid,p,i << 1); if(p > mid) update(mid + 1,r,p,i << 1 | 1); sum[i] = sum[i << 1] + sum[i << 1 | 1]; C[i] = C[i << 1] + C[i << 1 | 1]; } int query(int l,int r,int k,int i){ if(l == r) return k >= sum[i] ? C[i] : C[i] / sum[i] * k; int ans = 0,mid = (l + r) >> 1; if(sum[i << 1 | 1] >= k){ ans += query(mid + 1,r,k,i << 1 | 1); } else{ ans += C[i << 1 | 1]; ans += query(l,mid,k - sum[i << 1 | 1],i << 1); } return ans; } int en; int getId(int x){ return lower_bound(K + 1,K + 1 + en,x) - K; } int main() { int n,M; while(~scanf("%d%d",&n,&M)){ clr(sum,0); clr(C,0); for(int i = 1;i <= n;++ i){ scanf("%d",&t[i]); K[i] = t[i]; } sort(K + 1,K + 1 + n); en = unique(K + 1,K + 1 + n) - K - 1; int sum = 0; for(int i = 1;i <= n;++ i){ if(i == 1){ printf("0 "); update(1,en,getId(t[i]),1); sum += t[i]; continue; } int l = 0,r = i - 1; int ans = r; while(l <= r){ int mid = (l + r) >> 1; // debug(mid); // debug(query(1,en,mid,1)); if(M - (sum - query(1,en,mid,1)) >= t[i]){ ans = min(ans,mid); r = mid - 1; } else l = mid + 1; } printf("%d ",ans); update(1,en,getId(t[i]),1); sum += t[i]; } printf("n"); } return 0; }
最后
以上就是多情向日葵最近收集整理的关于Codeforces 1185 C2. Exam in BerSU (hard version)(权值线段树 + 二分 查询前 K 大的和)的全部内容,更多相关Codeforces内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复