学oi这么多月了第一次场切黄题(尽管不会哈希做法用的是侥幸没被出题人卡掉的umap),所以打算写篇题解,顺带着测试一下自己blog的可用性(反正也没有人看)(连LaTeX都不支持可用个鬼啊)

根据题面,假设两个点在第tt秒相遇,则编号为iiAA类点在第tt秒时的坐标为(i,ait)(i,a_i\cdot t),编号为jjBB类点在第tt秒时的坐标则为(bjt,j)(b_j\cdot t,j)。显然,当同时满足i=bjti=b_j\cdot tj=aitj=a_i\cdot t时,两点能在第tt秒相遇。可以把上式变形为t=ibj=jait=\frac {i} {b_j}=\frac {j} {a_i}


到这里就是第一个坑点了,t不一定是一个整数,所以不能直接计算ibj\frac {i} {b_j}jai\frac {j} {a_i}的值,c++中除法的自动取整会把两个互不相等的tt取成同一个整数。于是可以想到把等式两边同时乘以bjaib_j\cdot a_i,得到iai=jbji\cdot a_i=j\cdot b_j,由于iaii\cdot a_i的上界为106×109=101510^6\times 10^9 = 10^{15},不能直接开数组存储数据,所以直接开umap在输入aia_i时记录每个iaii\cdot a_i出现的次数,在输入bjb_j时直接求解即可。由于umap查询操作时间复杂度是一个常数,所以时间复杂度近似为O(k(n+m))O(k(n+m)),可以通过本题,不过最慢的点达到了800ms,对于n+m2×106n+m\leq 2\times10^6的数据范围还是显得太久了,正解的哈希做法应该会快一些。


另外男酿神犇@kamisako提出了一种复杂度为O(nlogn)O(nlogn)的做法:离散化之后桶排,但我不会离散化,所以细节可以问他。


另外还需要注意一个特判,当aia_ibj=0b_j=0时点iijj会永远静止,无法与任何一个点相遇,所以输入时遇到00直接continue即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
unordered_map <ll,int> leg; //a(i)*i出现的次数
ll read(){}//快读,此处略去
ll a,b;
signed main(){
int n,m;
n=read();m=read();
for(int i=1;i<=n;i++){
a=read();
if(a<=0) continue; //特判
leg[a*i]++;
}
int cnt = 0;
for(int j=1;j<=m;j++){
b=read();
if(b<=0) continue;
cnt+=leg[b*j];
}
printf("%d",cnt);
return 0;
}