231023校内赛
T1 区间
题解
很容易想到的一点是如果 \(k\) 足够大,那么把区间单独放到一个组里总比多个区间在一个组优
对于多个区间来说,区间之间如果两两不包含的话这道题会是比较好做的
就可以注意到如果一个大区间包含了一个小区间,那么大区间要么单独一组,要么和小区间同一组,这样会是比较优的选择
所以只需要对小区间做 dp ,求出 \(f_i\) 表示小区间形成了 \(i\) 组的最大贡献,然后把前 \(k−i\) 大的大区间每一个单独一组即可
小区间设 \(f_{i,j}\) 表示现在分了 \(i\) 组,考虑了前 \(j\) 个区间的最大贡献。每个 \(i\) 分别单调队列即可省掉一维并优化复杂度
到底是谁出的这么难想的第一题
#include<bits/stdc++.h>
#define N 5010
#define inf (1e9)
using namespace std;
struct node{
int l,r;
}a[N],p[N];
int n,k,m,ans,tot,mx,len[N],f[N],g[N],top,last,stk[N];
bool cmp(node x,node y){
return x.r==y.r?x.l>y.l:x.r<y.r;
}
bool great(int x,int y){
return x>y;
}
void solve(){
for(int i = 1;i<=n;i++) f[i] = -inf;
for(int i = 1;i<=k;i++){
top = 0;last = 1;g[0] = -inf;
for(int j = 1;j<=n;j++){
while(top&&f[stk[top]-1]+p[stk[top]].r<=f[j-1]+p[j].r) top--;
stk[++top] = j;
last = min(top,last);
while(p[stk[last]].r<=p[j].l) last++;
g[j] = f[stk[last]-1]+p[stk[last]].r-p[j].l;
}
for(int j = 0;j<=n;j++) f[j] = g[j];
ans = max(ans,f[n]+len[k-i]);
}
}
int main(){
freopen("interval.in","r",stdin);
freopen("interval.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(int i = 1;i<=n;i++)
cin>>a[i].l>>a[i].r;
sort(a+1,a+n+1,cmp);
tot = mx = 0;
for(int i = 1;i<=n;i++){
if(!tot||mx<a[i].l){
mx = a[i].l;
p[++tot] = a[i];
}else len[++m] = a[i].r-a[i].l;
}
sort(len+1,len+m+1,great);
for(int i = 1;i<=m;i++)
len[i]+=len[i-1];
for(int i = m+1;i<=k;i++)
len[i] = -inf;
n = tot;
solve();
cout<<ans;
return 0;
}
T2妹子
题解
对于一个序列来说,它的最大值一定是单调不降的
所以很容易会往二分上想
那么对于一个决策点来说,如果左边的 \(a\) 序列的最大值比右边的 \(b\) 序列的最大值大
二分的时候那就应该把 \(mid\) 左移
反之,右移
对于这个二分,你可以在线段树上实现,做到 \(\mathcal O(n\log n)\) 的复杂度
也可以不在线段树上实现,只不过是 \(\mathcal O(n\log^2 n)\) 罢了
#include<bits/stdc++.h>
#define ll long long
#define inf (0x5fffffff)
#define N 500010
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
struct tree{
int a[N];
struct node{
int l,r;
ll mx,flag;
}t[N<<2];
void pushnow(int p,ll v){
t[p].mx+=v;
t[p].flag+=v;
}
void pushdown(int p){
if(t[p].flag){
pushnow(lc,t[p].flag);
pushnow(rc,t[p].flag);
t[p].flag = 0;
}
}
void build(int p,int l,int r){
t[p].l = l,t[p].r = r;
t[p].mx = -inf;t[p].flag = 0;
if(l==r){
t[p].mx = a[l];
return ;
}
int mid = (l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
t[p].mx = max(t[lc].mx,t[rc].mx);
}
ll query(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r)
return t[p].mx;
pushdown(p);
ll ans = -inf,mid = (t[p].l+t[p].r)>>1;
if(l<=mid) ans = max(ans,query(lc,l,r));
if(r>mid&&ans<t[rc].mx) ans = max(ans,query(rc,l,r));
return ans;
}
void add(int p,int l,int r,int v){
if(t[p].l>=l&&t[p].r<=r){
pushnow(p,v);
return ;
}
pushdown(p);
int mid = (t[p].l+t[p].r)>>1;
if(l<=mid) add(lc,l,r,v);
if(r>mid) add(rc,l,r,v);
t[p].mx = max(t[lc].mx,t[rc].mx);
}
}T1,T2;
int n,m;
int main(){
freopen("girl.in","r",stdin);
freopen("girl.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i = 1;i<=n;i++)
cin>>T1.a[i];
for(int i = 1;i<=n;i++)
cin>>T2.a[i];
T1.build(1,1,n);T2.build(1,1,n);
for(int i = 1;i<=m;i++){
char opt;int ql,qr,v;
cin>>opt>>ql>>qr>>v;
if(opt=='A') T1.add(1,ql,qr,v);
else T2.add(1,ql,qr,v);
cin>>ql>>qr;
int l = ql-1,r = qr;
while(l<r){
int mid = (l+r)>>1;
if(T1.query(1,ql,mid)>T2.query(1,mid+1,qr)) r = mid;
else l = mid+1;
}
cout<<min(T1.query(1,ql,r),T2.query(1,r,qr))<<"\n";
}
return 0;
}
T3 数对
题解
对于这个题有一个结论就是按 \(a+b\) 排序一定是最优的
因为可以分类讨论一下对于 \(a,b\) 大小关系的四种情况,就能得出这个结论
自己手写一下,挺简单的,我就不说了我是真的懒
然后其实就是 \(dp\) 的事了
设 \(f_{i,j}\) 表示前 \(i\) 个数中,已选的数的 \(\max(a) = j\) ,最多选了多少个数
转移时只需要更新选了第 \(i\) 个数的情况,分别考虑 \(j\le \min(a_i,b_i)\) 和 \(a_i< j \le b_i\)
用线段树维护即可做到 \(\mathcal O(n \log n)\)
#include<bits/stdc++.h>
#define N 100010
#define ll long long
using namespace std;
struct node{
int a,b;ll p;
}a[N];
struct tree{
#define lc (p<<1)
#define rc ((p<<1)|1)
struct node{
int l,r;
ll mx,flag;
}t[N<<4];
void pushnow(int p,ll v){
t[p].mx+=v;
t[p].flag+=v;
}
void pushdown(int p){
if(t[p].flag){
pushnow(lc,t[p].flag);
pushnow(rc,t[p].flag);
t[p].flag = 0;
}
}
void build(int p,int l,int r){
t[p].l = l,t[p].r = r;
if(l==r) return ;
int mid = (l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
t[p].mx = max(t[lc].mx,t[rc].mx);
}
ll query(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r)
return t[p].mx;
pushdown(p);
ll ans = 0,mid = (t[p].l+t[p].r)>>1;
if(l<=mid) ans = max(ans,query(lc,l,r));
if(r>mid&&ans<t[rc].mx) ans = max(ans,query(rc,l,r));
return ans;
}
void add(int p,int l,int r,ll v){
if(t[p].l>=l&&t[p].r<=r){
pushnow(p,v);
return ;
}
pushdown(p);
int mid = (t[p].l+t[p].r)>>1;
if(l<=mid) add(lc,l,r,v);
if(r>mid) add(rc,l,r,v);
t[p].mx = max(t[lc].mx,t[rc].mx);
}
void change(int p,int x,ll v){
if(t[p].l==t[p].r&&t[p].l==x){
t[p].mx = max(t[p].mx,v);
return ;
}
pushdown(p);
int mid = (t[p].l+t[p].r)>>1;
if(x<=mid) change(lc,x,v);
else change(rc,x,v);
t[p].mx = max(t[lc].mx,t[rc].mx);
}
}T;
int n,m,w[N<<2];
bool cmp(node x,node y){
return x.a+x.b<y.a+y.b;
}
int main(){
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 1;i<=n;i++){
cin>>a[i].a>>a[i].b>>a[i].p;
w[++m] = a[i].a;
w[++m] = a[i].b;
}
sort(w+1,w+m+1);
m = unique(w+1,w+m+1)-w-1;
for(int i = 1;i<=n;i++){
a[i].a = lower_bound(w+1,w+m+1,a[i].a)-w;
a[i].b = lower_bound(w+1,w+m+1,a[i].b)-w;
}
sort(a+1,a+n+1,cmp);
T.build(1,1,m);
for(int i = 1;i<=n;i++){
int tmp = min(a[i].a,a[i].b);
ll j = T.query(1,1,tmp)+a[i].p;
T.change(1,a[i].a,j);
if(tmp<a[i].b) T.add(1,tmp+1,a[i].b,a[i].p);
}
cout<<T.query(1,1,m);
return 0;
}
T4
摆了,不写
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17785581.html