1 条题解
-
0
水篇题解。
感觉已经好久好久没写过黄题题解了吧。
日常看错题之当我以为一个猴子在点 时要以 的方向移动然后思考许久无果看了眼样例发现:哦我又看错题了。
感觉是比较一眼的题目。
当然这建立在你题看对了的情况下。一个点只会朝着一个方向永远移动,所以相遇只有两种情况:
-
相向而行的相遇:
- 这要求两点中,最初位于左侧的点是往右走,最初位于右侧的点是往左走。
- 且两点之间的间隔 为偶数(奇数的话会擦边而过,但无法在整点上相遇),还要求 (否则在 时间内也无法相遇)。
-
同向而行的相遇:
- 正常来讲,同向而行能相遇是因为一个快一个慢。
- 但是这道题中,所有点的移动速度都是 ,这也就不存在“追及”情况了,也就是说,两个同向而行的点能相遇,当且仅当其初始点位置相同。也就是两个本质一样的点。
那么就可以做了,维护三个数组 ,分别存储:
- 存储所有往右走的点;
- 存储所有往左走且初始点位为偶数的点;
- 存储所有往左走且初始点位为奇数的点。
对这三个序列升序排序之后,就很好做了。
相向而行的,枚举 中的点 ,在对应的 数组(根据 的奇偶性判断是 还是 )内二分到对应区间 所含有的点数,累加答案即可。
同向而行的,只需要分往左还是往右,对下标开两个桶记录一下,贡献 。
整个还是非常好做的。
代码里有一些辅助理解的注释喵。
::::success[code && submission]
#include<bits/stdc++.h> #define LL long long #define UInt unsigned int #define ULL unsigned long long #define LD long double #define pii pair<int,int> #define pLL pair<LL,LL> #define pDD pair<LD,LD> #define fr first #define se second #define pb push_back #define isr insert #define _i128 __int128 using namespace std; const int N = 2e5+5; LL n,k,p[N],Ans;//不开 LL 见祖宗 vector<LL> L[2],R;//其实应该开数组的但是实在不想写三个长度变量 map<LL,LL> t[2];//充当桶解决重复点的问题 int read(){ int su=0,pp=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();} while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();} return su*pp; } int main(){ n=read(),k=read(); for(int i=1;i<=n;i++)p[i]=read(); //注意 vector 的下标从 0 开始!! for(int i=1;i<=n;i++){ char opt;cin>>opt; if(opt=='R')R.pb(p[i]); else L[p[i]&1].pb(p[i]); //按点位的奇偶性分类 //因为中间间隔路程只能是偶数(两只猴子都在移动) t[(opt=='L'?0:1)][p[i]]++;//塞进桶 } sort(R.begin(),R.end()); sort(L[0].begin(),L[0].end()); sort(L[1].begin(),L[1].end()); for(LL x:R){ //以往右走的为指定物,找右侧奇偶性匹配且距离不长的猴子 int o=(x&1);//奇偶性判定 int l=lower_bound(L[o].begin(),L[o].end(),x)-L[o].begin(); int r=upper_bound(L[o].begin(),L[o].end(),x+2*k)-L[o].begin()-1; //找到能相遇的猴子的左右端点 //注意右端点要用 upper_bound 最后 -1 因为可能有重复! Ans+=r-l+1;//累加答案 } for(int o=0;o<2;o++)//左右方向 for(auto [x,y]:t[o])Ans+=y*(y-1)/2;//累加答案 cout<<Ans<<"\n"; return 0; }::::
如果本篇题解对你有帮助的话,麻烦你点一个小小的赞,真是太感谢啦!
-
- 1
信息
- ID
- 12593
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者