Date:2022.04.02
题意描述:
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:
ts id
表示在 ts 时刻编号 id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数 N,D,K。
以下 N 行每行一条日志,包含两个整数 ts 和 id。
输出格式
按从小到大的顺序输出热帖 id。
每个 id 占一行。
数据范围
1≤K≤N≤105,
0≤ts,id≤105,
1≤D≤10000
输入样例:
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出样例:
1
3
思路①:
O
(
N
2
)
O(N^2)
O(N2)
枚举每一个时间点
t
t
t,看
[
t
,
t
+
d
)
[t,t+d)
[t,t+d)范围内所有
i
d
id
id有哪些出现了
>
=
k
>=k
>=k次的即为热帖。由于每次要枚举所有
i
d
id
id并统计所有
i
d
id
id的数量,所以每次要
m
e
m
s
e
t
memset
memset一下
i
d
id
id。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL sum[N],cnt[N],n,k,d,a[N],b[N];
bool st[N];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>d>>k;LL maxt=0,maxid=0;
for(int i=1;i<=n;i++)
{
cin>>zan[i].ts>>zan[i].id;
maxt=max(maxt,zan[i].ts);
}
for(int t=0;t<=maxt;t++)
{
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)
{
LL id=zan[i].id;
if(zan[i].ts>=t&&zan[i].ts<t+d) cnt[id]++;
if(cnt[id]>=k) {st[id]=true;continue;}
}
}
LL ans=0;
for(int i=0;i<N;i++)
if(st[i]) cout<<i<<'\n';
return 0;
}
思路②:
O
(
N
)
O(N)
O(N)。
暴力的瓶颈有两个:
1.枚举的是所有时间,若数据按
t
s
ts
ts排序后是多个1、100000显然枚举所有时间不明智。(当然如果硬说,这个算是软优化)
2.每次都要统计所有
i
d
id
id在这个时间段的出现次数,所以每次要枚举
n
n
n个数也要
m
e
m
s
e
t
memset
memset一下,复杂度自然多一维。
我们将所有点赞按时间为第一关键字排序,这样我们可以用双指针每次来动态维护一个时间在
[
t
,
t
+
d
)
[t,t+d)
[t,t+d)内的区间,但是双指针的
i
、
j
i、j
i、j是所有赞的编号。这样一来,每次后面的
j
+
+
j++
j++,而且对应的
c
n
t
[
z
a
n
[
j
]
.
i
d
]
+
+
cnt[zan[j].id]++
cnt[zan[j].id]++,并且每次将时间的右界变为
z
a
n
[
j
]
.
t
s
zan[j].ts
zan[j].ts,由此左边
i
i
i对应的
z
a
n
[
i
]
.
t
s
zan[i].ts
zan[i].ts如果不满足
z
a
n
[
j
]
.
t
s
−
z
a
n
[
i
]
.
t
s
<
d
zan[j].ts-zan[i].ts<d
zan[j].ts−zan[i].ts<d那就不要它了,对应的
c
n
t
[
z
a
n
[
i
]
.
i
d
]
−
−
cnt[zan[i].id]--
cnt[zan[i].id]−−,之后
i
+
+
i++
i++。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL cnt[N],n,m,t,k,d;
bool st[N];
struct node
{
LL ts,id;
bool operator<(const node&t)const
{
if(ts!=t.ts) return ts<t.ts;
return id<t.id;
}
}zan[N];
int main()
{
cin>>n>>d>>k;
for(int i=1;i<=n;i++)
cin>>zan[i].ts>>zan[i].id;
sort(zan+1,zan+1+n);
LL i,j;
for(i=1,j=1;i<=n;)
{
cnt[zan[i].id]++;
while(zan[i].ts-zan[j].ts>=d)
{
cnt[zan[j].id]--;
j++;
}
if(cnt[zan[i].id]>=k) st[zan[i].id]=true;
i++;//放最后
}
for(int i=0;i<N;i++)
if(st[i]) cout<<i<<'\n';
return 0;
}