Lanqiaoカップログ統計定規を取る方法
これは、2018 Lanqiao CupC言語地方大会グループBの8番目の質問です。
タイトルの説明
XiaoMingは、プログラマーフォーラムを維持しています。現在、彼は合計N行の「いいね」ログを収集しました。
各行の形式は次のとおりです。tsid。ts時に投稿番号が付けられたIDが「いいね」を受け取ったことを示します。
Xiao Mingは、かつて「ホットな投稿」だった投稿を数えたいと考えています。
投稿が長さDのいずれかの期間にK件以上のいいねを受け取った場合、XiaoMingはその投稿がかつて「ホット投稿」であったと見なします。
具体的には、[T、T + D)の期間中に投稿がK件以上のいいねを受け取ることを満足する特定のモーメントTがある場合(左が閉じ、右が開いていることに注意)、投稿はかつて「ホットポスト」。
ログがあれば、XiaoMingがかつて「ホットな投稿」だったすべての投稿番号を数えるのを手伝ってください。
入力
最初の行には、3つの整数N、D、およびKが含まれています。
次のN行には、1行に1つのログがあり、2つの整数tsとidが含まれています。
1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000
出力
ホットポストIDが昇順で出力されます。IDごとに1行。
サンプル入力710
2
0 1
0 10
10 10
10 1
9
1100
3100 3
サンプル出力
1
3
アイデア:私のアイデアは、各IDの同じ時間を2次元配列に格納することです。つまり、maps [id] [] = tsです。次に、ルーラーメソッドを使用して、maps配列に従って各IDの条件を決定します。要件を満たしている場合は、それが答えです。
配列の検索を減らすために、表示されたID番号を格納するセットを導入し、表示されたID番号に関連付けられた配列を照会しました。
ルーラーの選択:サブセットの最初と最後の位置を連続セットに設定してから、最初と最後の位置を進めて、修飾されたサブセットを見つけることだと思います。この質問では時差を計算する必要があるため、データは順番に並べられている必要があります。以下のコードでは、sortを使用してマップ配列を並べ替えています。
ACコード:
#include <bits/stdc++.h>
using namespace std;
vector<int>maps[100001]; //二维数组储存每个节点的被点赞的时间 maps[x][0]就是x号帖子第一次被点赞的时间
set<int>alls; //储存出现的帖子编号 与maps配合 避免不必要的查询 直接maps[alls][]就行
int main()
{
int n,d,k,ts,id;
scanf("%d %d %d",&n,&d,&k);
while(n--)
{
scanf("%d %d",&ts,&id);
alls.insert(id); //储存出现的id号
maps[id].push_back(ts); //将点赞时间储存至maps[id][]
}
for(set<int>::iterator iter=alls.begin();iter!=alls.end();iter++) //对整个maps[alls][]数组进行排序 方便后面的时间统计
{
sort(maps[*iter].begin(),maps[*iter].end()); //对有数据的数组进行排序 即 maps[alls][]
}
for(set<int>::iterator iter=alls.begin();iter!=alls.end();iter++) //对有数据的maps数组进行查找
{
int all=0,first=0,end=0; //点赞数量 第一个赞的位置 最后一个赞的位置
while(1) //尺取法
{
while(all<k&&end<maps[*iter].size()) //点赞数小于要求 && 数组里的数据还没有统计完
{
all++;
end++;
}
if(all<k) //统计完了 赞也不够
break;
if(maps[*iter][end-1]-maps[*iter][first]<d) //赞够 并且 第一个赞和末尾赞的时间相隔符合要求
{
printf("%d\n",*iter); //由于set有序 所以直接输出即可
break;
}
all--;
first++;
}
}
return 0;
}