P8661 [蓝桥杯 2018 省 B] 日志统计

题目传送门:P8661 [蓝桥杯 2018 省 B] 日志统计

提供一个与其他题解都不同的做法。

思路:

  1. 先把输入的日志先按编号从小到大排序,编号相同再按时间从小到大排序。

  2. 在排过序的结构体中,从 \(1\)\(n\) 枚举区间右端点 \(r\),以帖子曾经是“热帖”的最小区间长度(最小点赞数)\(k\) 确定区间左端点 \(l=r-k+1\),判断几种情况:

  • \(l<1\),则不存在该区间,该区间非法;
  • \(l\) 所属帖子的编号与 \(r\) 所属帖子的编号不同,该区间非法;
  • \(l\) 所属帖子的点赞时间与 \(r\) 所属帖子的点赞时间相差不小于 \(d\)(大于等于 \(d\)),该区间非法;
  • 若这个帖子已经被评为热帖(这个帖子的编号被输出过),该区间非法。

若这个区间以上任何一个条件都不满足,则这个区间合法,输出这个帖子的编号(\(r\) 所属帖子的编号)。

同时,这种输出方法也满足按从小到大的顺序输出热帖 \(id\)

Code:

AC 记录


无注释

P8661 Code


有注释

#include<bits/stdc++.h>

using namespace std; 

int n,d,k;//题意

struct node { int t,id; } a[1<<20]; //结构体存
bool cmp(node x,node y) { return x.id<y.id||(x.id==y.id&&x.t<y.t); }
//对结构体 node 进行排序:
//先按编号从小到大排序,编号相同再按时间从小到大排序

bool vis[1<<20]; //记录编号是否输出过

signed main()
{
	cin>>n>>d>>k; //输入
    for(int i=1;i<=n;i++) cin>>a[i].t>>a[i].id; //输入

    sort(a+1,a+1+n,cmp);//排序

    for(int i=1;i<=n;i++)//枚举右端点
    {   
        int l=i-k+1,r=i;
        //枚举区间 [l(i-k+1),r(i)],保证此区间点赞数恒为 k

        if(l<1) continue;
        //如果 l 不合法(比一小),开始下一次循环

        if(a[l].id!=a[r].id) continue;
        //如果 l 与 r 所属帖子 id 不同,此区间不合法,开始下一次循环

        if(a[r].t-a[l].t>=d) continue;
        //如果两次点赞时间间隔 >= d,此区间不合法,开始下一次循环

        if(vis[a[l].id]) continue;
        //如果这个 id 被记录过(被输出过),开始下一次循环

        //合法情况
        cout<<a[l].id<<endl; //输出
        vis[a[l].id]=1; //记录
    }
	return 0;
}

posted @ 2025-02-08 16:38  Wy_x  阅读(17)  评论(0)    收藏  举报