Codeforces_799
A.求两个时间比较一下。
#include<bits/stdc++.h> using namespace std; int n,t,k,d; int main() { ios::sync_with_stdio(false); cin >> n >> t >> k >> d; int tt = n/k; if(n%k) tt++; int sum1 = tt*t; int t1 = 0,t2 = d,now = 0; while(now < tt) { if(t1 < t2) t1 += t; else t2 += t; now++; } int sum2 = max(t1,t2); if(sum1 > sum2) cout << "YES" << endl; else cout << "NO" << endl; return 0; }
B.按价格排序,预记录每种颜色的位置,询问的时候保存前一个可行的位置,线性扫即可。
#include<bits/stdc++.h> using namespace std; int n,m,pos[5][200005],ok[200005] = {0}; struct xx { int p,a,b; friend bool operator <(xx a,xx b) { return a.p < b.p; } }a[200005]; int main() { ios::sync_with_stdio(false); cin >> n; for(int i = 1;i <= n;i++) cin >> a[i].p; for(int i = 1;i <= n;i++) cin >> a[i].a; for(int i = 1;i <= n;i++) cin >> a[i].b; sort(a+1,a+1+n); int cnt[5] = {0}; for(int i = 1;i <= n;i++) { int x = a[i].a,y = a[i].b; pos[x][++cnt[x]] = i; if(x != y) pos[y][++cnt[y]] = i; } cin >> m; int now[5] = {1,1,1,1,1}; while(m--) { int x; cin >> x; while(ok[pos[x][now[x]]]) now[x]++; if(now[x] > cnt[x]) cout << -1 << " "; else { ok[pos[x][now[x]]] = 1; cout << a[pos[x][now[x]]].p << " "; } } return 0; }
C.分三种情况
1.两堆各取一个,直接遍历取每堆的符合要求的最大b值。
2.在A堆取2个。先按p小到大排序,然后从头到尾枚举一个c,二分符合要求的c-p值最后一个的位置,在这一段rmq找最大的b值,更新最大的和。
3.在B堆取2个,同上。
#include<bits/stdc++.h> using namespace std; int n,c,d; int maxdp1[100005][20],maxdp2[100005][20]; struct xx { int b,x; xx(){}; xx(int bb,int xx):b(bb),x(xx){}; friend bool operator <(xx a,xx b) { return a.x < b.x; } }a[100005],b[100005]; void rmq_init1(int len) { for(int i = 1;i <= len;i++) maxdp1[i][0] = a[i].b; for(int j = 1;(1<<j) <= len;j++) { for(int i = 1;i+(1<<j)-1 <= len;i++) { maxdp1[i][j] = max(maxdp1[i][j-1],maxdp1[i+(1<<(j-1))][j-1]); } } } void rmq_init2(int len) { for(int i = 1;i <= len;i++) maxdp2[i][0] = b[i].b; for(int j = 1;(1<<j) <= len;j++) { for(int i = 1;i+(1<<j)-1 <= len;i++) { maxdp2[i][j] = max(maxdp2[i][j-1],maxdp2[i+(1<<(j-1))][j-1]); } } } int rmq_max1(int l,int r) { int k = (int)(log((double)(r-l+1))/log(2.0)); return max(maxdp1[l][k],maxdp1[r-(1<<k)+1][k]); } int rmq_max2(int l,int r) { int k = (int)(log((double)(r-l+1))/log(2.0)); return max(maxdp2[l][k],maxdp2[r-(1<<k)+1][k]); } int main() { ios::sync_with_stdio(false); cin >> n >> c >> d; int cnt1 = 0,cnt2 = 0; for(int i = 1;i <= n;i++) { int x,y; string s; cin >> x >> y >> s; if(s == "C") { a[++cnt1].b = x; a[cnt1].x = y; } else { b[++cnt2].b = x; b[cnt2].x = y; } } int maxx = 0; int pos1 = -1,max1 = 0; for(int i = 1;i <= cnt1;i++) { if(a[i].x <= c && a[i].b > max1) { pos1 = i; max1 = a[i].b; } } int pos2 = -1,max2 = 0; for(int i = 1;i <= cnt2;i++) { if(b[i].x <= d && b[i].b > max2) { pos2 = i; max2 = b[i].b; } } if(pos1 != -1 && pos2 != -1) maxx = max1+max2; sort(a+1,a+1+cnt1); sort(b+1,b+1+cnt2); rmq_init1(cnt1); rmq_init2(cnt2); if(cnt1 > 1 && a[1].x+a[2].x <= c) { for(int i = 1;i <= cnt1;i++) { if(a[i].x >= c) break; int t = upper_bound(a+1,a+cnt1+1,xx(0,c-a[i].x))-a-1; if(t <= i) break; maxx = max(maxx,a[i].b+rmq_max1(i+1,t)); } } if(cnt2 > 1 && b[1].x+b[2].x <= d) { for(int i = 1;i <= cnt2;i++) { if(b[i].x >= d) break; int t = upper_bound(b+1,b+cnt2+1,xx(0,d-b[i].x))-b-1; if(t <= i) break; maxx = max(maxx,b[i].b+rmq_max2(i+1,t)); } } cout << maxx << endl; return 0; }
还有一种方法,直接树状数组维护最大前缀max。
#include <bits/stdc++.h> using namespace std; int n,c,d,C[100005],D[100005]; inline int lowbit(int x) { return x & (-x); } void update(int tree[],int pos,int x) { while(pos <= 100000) { tree[pos] = max(tree[pos],x); pos += lowbit(pos); } } int getmax(int tree[],int pos) { int ans = INT_MIN; while(pos > 0) { ans = max(ans,tree[pos]); pos -= lowbit(pos); } return ans; } int main() { ios::sync_with_stdio(false); cin >> n >> c >> d; for(int i = 1;i <= 100000;i++) { C[i] = INT_MIN; D[i] = INT_MIN; } int ans = 0; while(n--) { int b,p,t; string s; cin >> b >> p >> s; if(s == "C") { if(p > c) continue; t = max(getmax(C,c-p),getmax(D,d)); update(C,p,b); } else { if(p > d) continue; t = max(getmax(C,c),getmax(D,d-p)); update(D,p,b); } ans = max(ans,t+b); } cout << ans << endl; return 0; }
D.边长指数增长,我们需要的倍数很少,直接爆搜就可以了。
#include <bits/stdc++.h> using namespace std; int a,b,w,h,n,A[100005],ans; void dfs(int x,int y,int now,int nowx,int nowy) { if(nowx >= x && nowy >= y) { ans = min(ans,now); return; } if(now == n+1) return; if(A[now] == 2) { while(x > nowx) { nowx *= 2; now++; } while(y > nowy) { nowy *= 2; now++; } ans = min(ans,now); return; } if(x > nowx) dfs(x,y,now+1,nowx*A[now+1],nowy); if(y > nowy) dfs(x,y,now+1,nowx,nowy*A[now+1]); } int main() { ios::sync_with_stdio(false); cin >> a >> b >> w >> h >> n; for(int i = 1;i <= n;i++) cin >> A[i]; sort(A+1,A+1+n); reverse(A+1,A+1+n); ans = n+1; dfs((a-1)/h+1,(b-1)/w+1,0,1,1); dfs((a-1)/w+1,(b-1)/h+1,0,1,1); if(ans == n+1) cout << -1 << endl; else cout << ans << endl; return 0; }
E.把原数组分为4类,①A、M都不喜欢v0。②A喜欢、M不喜欢。③A不喜欢、M喜欢。④A、M都喜欢。
我们枚举④中的数量,然后计算剩余②③中最少数量,剩下的数从①②③中小的挑出。
枚举④的数量从大到小,这样②③个数肯定是递增的,因此就能使用上一次保存②③的个数。
#include<bits/stdc++.h> using namespace std; int n,m,k,a[200005]; int v0[200005],v1[200005],v2[200005],v3[200005]; long long sum0[200005] = {0},sum1[200005] = {0},sum2[200005] = {0},sum3[200005] = {0}; bool has1[200005] = {0},has2[200005] = {0}; int main() { ios::sync_with_stdio(false); cin >> n >> m >> k; for(int i = 1;i <= n;i++) cin >> a[i]; int x; cin >> x; while(x--) { int xx; cin >> xx; has1[xx] = 1; } cin >> x; while(x--) { int xx; cin >> xx; has2[xx] = 1; } int cnt0 = 0,cnt1 = 0,cnt2 = 0,cnt3 = 0; for(int i = 1;i <= n;i++) { if(has1[i] && has2[i]) v3[++cnt3] = a[i]; else if(has1[i]) v1[++cnt1] = a[i]; else if(has2[i]) v2[++cnt2] = a[i]; else v0[++cnt0] = a[i]; } sort(v0+1,v0+1+cnt0); sort(v1+1,v1+1+cnt1); sort(v2+1,v2+1+cnt2); sort(v3+1,v3+1+cnt3); for(int i = 1;i <= cnt0;i++) sum0[i] = sum0[i-1]+v0[i]; for(int i = 1;i <= cnt1;i++) sum1[i] = sum1[i-1]+v1[i]; for(int i = 1;i <= cnt2;i++) sum2[i] = sum2[i-1]+v2[i]; for(int i = 1;i <= cnt3;i++) sum3[i] = sum3[i-1]+v3[i]; long long ans = 1e18; int t1 = 0,t2 = 0; for(int i = min(cnt3,m);i >= 0;i--) { t1 = max(t1,k-i),t2 = max(t2,k-i); if(t1+t2+i > m || t1 > cnt1 || t2 > cnt2) break; if(cnt0+cnt1+cnt2+i < m) break; int t0 = 0; while(t0+t1+t2+i < m) { int t = m-t1-t2-i; if(cnt0 >= t && (t1 == cnt1 || v0[t] <= v1[t1+1]) && (t2 == cnt2 || v0[t] <= v2[t2+1])) {t0 = t;break;} else if(t1 < cnt1 && (t2 == cnt2 || v1[t1+1] <= v2[t2+1])) t1++; else t2++; } ans = min(ans,sum0[t0]+sum1[t1]+sum2[t2]+sum3[i]); } if(ans == 1e18) cout << -1 << endl; else cout << ans << endl; return 0; }