Blue Bridge Cup Selected Question Series - Log Statistics - Rule of Foot (2018 Provincial Competition)

First of all, before looking at the example, I will introduce a commonly used algorithm - the ruler method.

Ruler concept:

The ruler method, also known as two pointers and two pointers, is a commonly used optimization technique in algorithm competitions and is used to solve sequence interval problems. Simple operation and easy programming. In simple terms, the double loop can be transformed into a single loop, thereby increasing the time complexity from O(n 2 ) to O(n).

Take a chestnut:

First look at a double loop executed with i and j:

for(int i = 0; i < n; i++)           //i从头扫到尾
    for(int j = n-1; j >= 0; j--){
    
       //j从尾扫到头
        ......
    }

where i loops from 0​​​ to n−1​​​ and j in turn loops from n−1​​ to 0​​. The time complexity of these two loops is O(n 2 ).
The ruler method can process i, j together in a loop, the code is as follows, so the complexity is changed from O(n 2 ) to O(n).

for (int i = 0, j = n - 1; i < j; i++, j--) {
    
    
    ......
}

There is another way to write while():

//用while实现:
int i = 0, j = n - 1;
while (i < j) {
    
          //i和j在中间相遇。这样做还能防止i、j越界
        ......       //满足题意的操作
        i++;         //i从头扫到尾
        j--;         //j从尾扫到头
}

The above is just a reverse scan, suffering from another same-direction scan.
The Blue Bridge Cup boss made a summary, just look at the following to understand:

The circular pointers i and j are called scanning pointers . In the ruler method, these two pointers i and j have two scanning directions:
reverse scanning i and j in opposite directions, i from the beginning to the end, j from the end to the beginning, in Meet in the middle. The i and j pointers scanned in reverse can also be called left and right pointers .
Scan i and j in the same direction, from the beginning to the end, but at different speeds. For example, j can run in front of i. The i and j pointers scanned in the same direction can also be called fast and slow pointers . At this time, due to the different speeds of i and j, a sliding window of variable size is generated in the sequence between i and j , which is the advantage of the ruler method. There are flexible applications.
Note that the most important thing about using the ruler is that the two pointers i and j can only have one cycle on the whole, for example: i cycle once, and the corresponding j can only follow i cycle once. In this way, the optimization of computational complexity from O(n 2 ) to O(n)​ can be achieved.

Next is a real question in the provincial competition, using the python violence method, which is similar to the C++ ruler method:

Topic description

Xiao Ming maintains a programmers forum. Now he has collected a log of "likes" with N lines in total. The format of each line is:

ts id

Indicates that the post with the number id at time ts received a "like".

Now Xiao Ming wants to count which posts were once "hot posts". If a post has received no less than K likes in any time period of length D, Xiao Ming considers the post to be a "hot post".

Specifically, if there is a certain moment T that satisfies that the post receives no less than K likes within the period of [T, T+D) (note that it is in the left-closed and right-open interval), the post was once a "hot" post".

Given the log, please help Xiaoming to count all the post numbers that were "hot posts".

enter description

The first line contains three integers N, D, K.

The following N lines contain one log per line, containing two integers ts and id.

其中,1<=K<=N<=105,0<=ts<=105,0<=id<=105

output description

Output the hot post ids in ascending order. One row per id.

sample input

7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

Sample output

1
3

Detailed answer

Although we have introduced the ruler method above, this can be used as an understanding. The brute force method using python in this question is about the same complexity as the c++ ruler method, so here I first use the python brute force method (because the code is easy to write, hehe):

from bisect import bisect_left
maxn=int(1e5+50)
n,d,k=map(int,input().split())
m=[[] for _ in range(maxn)]
post=set()
for _ in range(n):
    ts,idd=map(int,input().split())
    post.add(idd)
    m[idd].append(ts)  #读每个帖子的赞的时间
post = sorted(post)    #对帖子id排序
for idd in post:       #检查每个帖子
    m[idd]=sorted(m[idd])  #把某个帖子的ts排序
    for i in range(len(m[idd])):   #暴力统计这个帖子是不是热帖
        td = m[idd][i]+d
        if(bisect_left(m[idd],td)-i >= k):
            print(idd)
            break

Guess you like

Origin blog.csdn.net/m0_51951121/article/details/122648992