USACO 2018JAN Silver

123 篇文章 0 订阅
53 篇文章 0 订阅

A.lifeguards(线段树+枚举)
枚举删掉哪条线段,离散化+线段树维护线段覆盖长度qaq
B.rental(贪心+二分+枚举)
枚举留几头牛,贪心算收益qaq
C.mootube(并查集+暴力)
类似最大生成树的并查集+暴力处理出dis,然后暴力回答询问qaq

A

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,a[N<<1],L[N],R[N],num=0,m,ans=0;
struct node{
    int len,covlen,cov;
}tr[N<<4];
inline void pushup(int p){
    if(tr[p].cov) return;
    tr[p].covlen=tr[p<<1].covlen+tr[p<<1|1].covlen;
}
inline void build(int p,int l,int r){
    if(l==r){tr[p].len=a[l+1]-a[l];return;}
    int mid=l+r>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
    tr[p].len=tr[p<<1].len+tr[p<<1|1].len;
}
inline void cover(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        tr[p].cov++;
        if(tr[p].cov==1) tr[p].covlen=tr[p].len;return;
    }int mid=l+r>>1;
    if(x<=mid) cover(p<<1,l,mid,x,y);
    if(y>mid) cover(p<<1|1,mid+1,r,x,y);
    pushup(p);
}
inline void del(int p,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        tr[p].cov--;
        if(tr[p].cov==0){
            if(l==r) tr[p].covlen=0;
            else pushup(p);
        }return;
    }int mid=l+r>>1;
    if(x<=mid) del(p<<1,l,mid,x,y);
    if(y>mid) del(p<<1|1,mid+1,r,x,y);
    pushup(p);
}
int main(){
    freopen("lifeguards.in","r",stdin);
    freopen("lifeguards.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i){
        a[++num]=L[i]=read();a[++num]=R[i]=read();
    }sort(a+1,a+num+1);m=unique(a+1,a+num+1)-a-1;build(1,1,m-1);
    for(int i=1;i<=n;++i){
        L[i]=lower_bound(a+1,a+m+1,L[i])-a;
        R[i]=lower_bound(a+1,a+m+1,R[i])-a;
        cover(1,1,m-1,L[i],R[i]-1);
    }for(int i=1;i<=n;++i){
        del(1,1,m-1,L[i],R[i]-1);
        ans=max(ans,tr[1].covlen);
        cover(1,1,m-1,L[i],R[i]-1);
    }printf("%d\n",ans);
    return 0;
}

B

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,r,a[N],b[N];
ll suma[N],sumb[N],sumx[N],sumc[N],ans=0;
struct node{
    int x,c;
}s[N];
inline bool cmp(int x,int y){return x>y;}
inline bool cmp1(node x,node y){return x.c>y.c;}
int main(){
    freopen("rental.in","r",stdin);
    freopen("rental.out","w",stdout);
    n=read();m=read();r=read();
    for(int i=1;i<=n;++i) a[i]=read();
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;++i) suma[i]=suma[i-1]+a[i];
    for(int i=1;i<=m;++i) s[i].x=read(),s[i].c=read();
    sort(s+1,s+m+1,cmp1);
    for(int i=1;i<=m;++i) sumx[i]=sumx[i-1]+s[i].x,sumc[i]=sumc[i-1]+(ll)s[i].c*s[i].x;
    for(int i=1;i<=r;++i) b[i]=read();
    sort(b+1,b+r+1,cmp);
    for(int i=1;i<=r;++i) sumb[i]=sumb[i-1]+b[i];
    for(int i=0;i<=n;++i){//留i头牛的最优收益
        if(n-i>r) continue;
        ll res=sumb[n-i];
        int pos=upper_bound(sumx+1,sumx+m+1,suma[i])-sumx-1;
        res+=sumc[pos];
        if(pos!=m) res+=(ll)s[pos+1].c*(suma[i]-sumx[pos]);
        ans=max(ans,res);
    }printf("%lld\n",ans);
    return 0;
}

C

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 5010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,dis[N][N],fa[N],sz[N];
vector<int>a[N];
struct edge{
    int x,y,val;
}e[N];
inline bool cmp(edge x,edge y){return x.val>y.val;}
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
    freopen("mootube.in","r",stdin);
    freopen("mootube.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;++i) fa[i]=i,a[i].push_back(i);
    for(int i=1;i<n;++i) e[i].x=read(),e[i].y=read(),e[i].val=read();
    sort(e+1,e+n,cmp);
    for(int ii=1;ii<=n-1;++ii){
        int xx=find(e[ii].x),yy=find(e[ii].y);
        if(a[xx].size()>a[yy].size()) swap(xx,yy);
        fa[xx]=yy;
        for(int i=0;i<a[xx].size();++i)
            for(int j=0;j<a[yy].size();++j){
                int x=a[xx][i],y=a[yy][j];
                dis[x][y]=dis[y][x]=e[ii].val;
            }
        for(int i=0;i<a[xx].size();++i) a[yy].push_back(a[xx][i]);
    }while(m--){
        int k=read(),x=read(),ans=0;
        for(int i=1;i<=n;++i) if(dis[x][i]>=k) ans++;
        printf("%d\n",ans);
    }
    return 0;
}
好的,这是一道经典的单调栈问题。题目描述如下: 有 $n$ 个湖,第 $i$ 个湖有一个高度 $h_i$。现在要在这些湖之间挖一些沟渠,使得相邻的湖之间的高度差不超过 $d$。请问最少需要挖多少个沟渠。 这是一道单调栈的典型应用题。我们可以从左到右遍历湖的高度,同时使用一个单调栈来维护之前所有湖的高度。具体来说,我们维护一个单调递增的栈,栈中存储的是湖的下标。假设当前遍历到第 $i$ 个湖,我们需要在之前的湖中找到一个高度最接近 $h_i$ 且高度不超过 $h_i-d$ 的湖,然后从这个湖到第 $i$ 个湖之间挖一条沟渠。具体的实现可以参考下面的代码: ```c++ #include <cstdio> #include <stack> using namespace std; const int N = 100010; int n, d; int h[N]; stack<int> stk; int main() { scanf("%d%d", &n, &d); for (int i = 1; i <= n; i++) scanf("%d", &h[i]); int ans = 0; for (int i = 1; i <= n; i++) { while (!stk.empty() && h[stk.top()] <= h[i] - d) stk.pop(); if (!stk.empty()) ans++; stk.push(i); } printf("%d\n", ans); return 0; } ``` 这里的关键在于,当我们遍历到第 $i$ 个湖时,所有比 $h_i-d$ 小的湖都可以被舍弃,因为它们不可能成为第 $i$ 个湖的前驱。因此,我们可以不断地从栈顶弹出比 $h_i-d$ 小的湖,直到栈顶的湖高度大于 $h_i-d$,然后将 $i$ 入栈。这样,栈中存储的就是当前 $h_i$ 左边所有高度不超过 $h_i-d$ 的湖,栈顶元素就是最靠近 $h_i$ 且高度不超过 $h_i-d$ 的湖。如果栈不为空,说明找到了一个前驱湖,答案加一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值