2022杭电多校3(总结+补题)

总结

又躺了一把多校,全程是队友在过题,我不仅没过题还提供了好多罚时,死磕的题目一直没磕出来。。。。

题解

1003 - Cyber Language

水题,输入字符串之后直接把每个单词的第一个字母大写输出即可。

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>t;
    cin.get();
    while(t--)
    {
        string ss;
        getline(cin,ss);
        int len=ss.length();
        for(int i=0;i<len;)
        {
            if(ss[i]!=' ')
            {
                cout<<(char)toupper(ss[i]);
                int j;
                for(j=i;j<len;j++)
                    if(ss[j]==' ')
                        break;
                i=j;
            }
            else
                i++;
        }
        cout<<endl;
    }   
    return 0;
}

1009 - Package Delivery

题意:

n n n 个快递,每个快递有相应的到达时间 l i l_i li 与最迟取快递的时间 r i r_i ri ,小 Q Q Q 每次最多可以取 k k k 个快递,问最少去取多少次快递能把所有快递拿回来。

做法:我们考虑当前未取的快递中 r r r 最小的一个,我们在 r r r 这天把快递取走一定不会使最终的结果变差,也就是说,每次我们在当前未取的快递中选一个 r r r 最小的快递,并在当天尽可能的取走尽量多的快递(取走的快递要标记), 迭代即可得到最少的取快递次数,这里我们使用优先队列维护,每次选定 r r r 之后都将到达时间小于等于 r r r 的快递的截止日期及快递编号丢进优先队列中,优先取截止时间小的。

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
#define tp3 tuple<int,int,int>
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        priority_queue<P,vector<P>,greater<P> >q;
        vector<tp3> a;
        vector<tp3> b;
        for(int i=0;i<n;i++)
        {
            int x,y;
            cin>>x>>y;
            a.emplace_back(x,y,i);
            b.emplace_back(x,y,i);
        }
        sort(b.begin(),b.end());//用于丢进优先队列
        sort(a.begin(),a.end(),[&](tp3 aa,tp3 bb)//按r从小到大排序,用于迭代
        {
            if(get<1>(aa)==get<1>(bb))
                return get<0>(aa)<get<0>(bb);
            return get<1>(aa) < get<1>(bb);
        });
        vector<int> vis(n,0);
        int j=0,ans=0;
        for(int i=0;i<n;i++)
        {
            int idx=get<2>(a[i]);
            if(!vis[idx])//找到r最小的未取快递
            {
                vis[idx]=1;
                int r=get<1>(a[i]);
                while(j<n&&get<0>(b[j])<=r)//将l<=r的快递丢进优先队列
                {
                    if(get<2>(b[j])==idx)
                    {
                        j++;
                        continue;
                    }
                    q.emplace(get<1>(b[j]),get<2>(b[j]));
                    j++;
                }
                int nb=1;
                ans++;
                while(!q.empty())//优先取截止时间小的
                {
                    if(nb==k)/取满k个或队列空即退出
                        break;
                    P aa=q.top();
                    q.pop();
                    if(!vis[aa.s])
                    {
                        vis[aa.s]=1;
                        nb++;
                    }
                }
            }
        }
        cout<<ans<<endl;
    }   
    return 0;
}

1011 - Taxi

题意:

n n n 个点,给出 n n n 个点的坐标 ( x i , y i ) (x_i,y_i) (xi,yi) w i w_i wi ,给出 q q q 个查询,每个查询给出一个点 ( x ’ , y ′ ) (x’,y') (x,y) ,求 v a l = m a x ( ∣ x ′ − x i ∣ + ∣ y ′ − y i ∣ , w i ) ( 1 ≤ i ≤ n ) val=max(|x'-x_i|+|y'-y_i|,w_i)(1\le i\le n) val=max(xxi+yyi,wi)(1in)

做法:

我们知道一个点与另一个点的曼哈顿距离 $= max(\left {(x+y)+(-x_i-y_i),(-x+y)+(x_i-y_i),(x-y)+(-x_i+y_i),(-x-y)+(x_i+y_i) \right } ) $

因此我们只需要记录 n n n 个点中 ( − x i − y i ) , ( x i − y i ) , ( − x i + y i ) , ( x i + y i ) (-x_i-y_i),(x_i-y_i),(-x_i+y_i),(x_i+y_i) (xiyi),(xiyi),(xi+yi),(xi+yi) 的最大值就可以 O ( 1 ) O(1) O(1) 得到 ( x ’ , y ’ ) (x’,y’) (x,y) n n n 个点的最长曼哈顿距离。我们再考虑有 w w w 的情况,我们将 n n n 个点按照 w w w 值从小到大排序,并记录每个点后缀 ( − x i − y i ) , ( x i − y i ) , ( − x i + y i ) , ( x i + y i ) (-x_i-y_i),(x_i-y_i),(-x_i+y_i),(x_i+y_i) (xiyi),(xiyi),(xi+yi),(xi+yi) 的最大值,再使用二分找到最大的 v a l val val

二分求出当前点到 m i d mid mid 的距离 d d d

w m i d < d w_{mid}<d wmid<d ,说明从 m i d mid mid n n n 之间的城镇中答案至少为 w m i d w_{mid} wmid ,因此可将 l l l 更新为 m i d + 1 mid+1 mid+1

w m i d > = d w_{mid}>=d wmid>=d ,说明从 m i d mid mid n n n 之间的城镇中答案至多为 w m i d w_{mid} wmid ,因此可将 r r r 更新为 m i d − 1 mid-1 mid1

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn=200010;
const int inf=0x3f3f3f3f;
const int mod=998244353;
int t;
int n,m,k;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--)
    {
        int q;
        cin>>n>>q;
        vector<vector<P> > a(4,vector<P>(n));
        for(int i=0;i<n;i++)
        {
            int x,y,w;
            cin>>x>>y>>w;
            a[0][i]=make_pair(w,-x-y);
            a[1][i]=make_pair(w,x-y);
            a[2][i]=make_pair(w,-x+y);
            a[3][i]=make_pair(w,x+y);
        }
        for(int i=0;i<4;i++)
            sort(a[i].begin(),a[i].end(),[&](P aa,P bb)//按w排序
            {
                return aa.f<bb.f;
            });
        vector<vector<int>> ma(4,vector<int>(n+1,-inf));
        for(int i=0;i<4;i++)//预处理四个值的后缀最大值
            for(int j=n-1;j>=0;j--)
                ma[i][j]=max(ma[i][j+1],a[i][j].s);
        while(q--)
        {
            int x,y;
            cin>>x>>y;
            vector<int> b(4);
            b[0]=x+y;
            b[1]=-x+y;
            b[2]=x-y;
            b[3]=-x-y;
            int ans=0;
            int l=0,r=n-1,mid,nb=0;
            while(l<=r)//二分
            {
                mid=(l+r)/2;
                int n1=-inf;
                for(int j=0;j<4;j++)
                    n1=max(n1,ma[j][mid]+b[j]);
                if(a[0][mid].f<n1)
                {
                    l=mid+1;
                    nb=max(nb,a[0][mid].f);
                }
                else
                {
                    r=mid-1;
                    nb=max(nb,n1);
                }
            }
            ans=max(ans,nb);
            cout<<ans<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值