总结
又躺了一把多校,全程是队友在过题,我不仅没过题还提供了好多罚时,死磕的题目一直没磕出来。。。。
题解
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(∣x′−xi∣+∣y′−yi∣,wi)(1≤i≤n)
做法:
我们知道一个点与另一个点的曼哈顿距离 $= 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) (−xi−yi),(xi−yi),(−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) (−xi−yi),(xi−yi),(−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 mid−1
代码:
/*
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;
}