洛谷 P9914 题解
发表于|更新于
|阅读量:
学oi这么多月了第一次场切黄题(尽管不会哈希做法用的是侥幸没被出题人卡掉的umap),所以打算写篇题解,顺带着测试一下自己blog的可用性(反正也没有人看)(连LaTeX都不支持可用个鬼啊)
根据题面,假设两个点在第t秒相遇,则编号为i的A类点在第t秒时的坐标为(i,ai⋅t),编号为j的B类点在第t秒时的坐标则为(bj⋅t,j)。显然,当同时满足i=bj⋅t且j=ai⋅t时,两点能在第t秒相遇。可以把上式变形为t=bji=aij。
到这里就是第一个坑点了,t不一定是一个整数,所以不能直接计算bji和aij的值,c++中除法的自动取整会把两个互不相等的t取成同一个整数。于是可以想到把等式两边同时乘以bj⋅ai,得到i⋅ai=j⋅bj,由于i⋅ai的上界为106×109=1015,不能直接开数组存储数据,所以直接开umap在输入ai时记录每个i⋅ai出现的次数,在输入bj时直接求解即可。由于umap查询操作时间复杂度是一个常数,所以时间复杂度近似为O(k(n+m)),可以通过本题,不过最慢的点达到了800ms,对于n+m≤2×106的数据范围还是显得太久了,正解的哈希做法应该会快一些。
另外男酿神犇@kamisako提出了一种复杂度为O(nlogn)的做法:离散化之后桶排,但我不会离散化,所以细节可以问他。
另外还需要注意一个特判,当ai或bj=0时点i或j会永远静止,无法与任何一个点相遇,所以输入时遇到0直接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; 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; }
|