#1129. Recommendation System【模拟 + 排序】

原题链接

Problem Description:

Recommendation system predicts the preference that a user would give to an item. Now you are asked to program a very simple recommendation system that rates the user’s preference by the number of times that an item has been accessed by this user.

Input Specification:

Each input file contains one test case. For each test case, the first line contains two positive integers: N N N ( ≤ 50 , 000 \leq 50,000 50,000), the total number of queries, and K K K ( ≤ 10 \leq 10 10), the maximum number of recommendations the system must show to the user. Then given in the second line are the indices of items that the user is accessing – for the sake of simplicity, all the items are indexed from 1 to N N N. All the numbers in a line are separated by a space.

Output Specification:

For each case, process the queries one by one. Output the recommendations for each query in a line in the format:

query: rec[1] rec[2] ... rec[K]

where query is the item that the user is accessing, and rec[i] (i=1, … K) is the i-th item that the system recommends to the user. The first K K K items that have been accessed most frequently are supposed to be recommended in non-increasing order of their frequencies. If there is a tie, the items will be ordered by their indices in increasing order.

Note: there is no output for the first item since it is impossible to give any recommendation at the time. It is guaranteed to have the output for at least one query.

Sample Input:

12 3
3 5 7 5 5 3 2 1 8 3 8 12

Sample Output:

5: 3
7: 3 5
5: 3 5 7
5: 5 3 7
3: 5 3 7
2: 5 3 7
1: 5 3 2
8: 5 3 1
3: 5 3 1
8: 3 5 1
12: 3 5 8

Problem Analysis:

动态维护有序序列, n n n 组询问,每组询问输出有序序列的前 m m m 个数。

本题中由于 m m m 规模比较小,可以维护一个长度为 m m m 的序列,新序列前 m m m 的数要么为序列中原本前 m m m 大的数,要么是新加上的数,每次快速排序一下整个序列即可,并且保证序列中元素不超过 m m m。时间复杂度为 O ( n ⋅ m log ⁡ m ) O(n\cdot m\log m) O(nmlogm)

实际上维护一个随时插入数的序列有序也可以使用插入排序 O ( n 1 ∼ 2 ) O(n^{1 \sim 2}) O(n12)

// 插入排序
/*
	第一个元素是有序的,
	从遍历第二 ~ 第 n 个元素,如果 a[i] < a[j],把 a[i] 插到 a[j] 的前边去,直到遍历完整理序列。
*/
int main()
{
    
    
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    for (int i = 2; i <= n; i ++ )
    {
    
    
        int j = i;
        while (j >= 1 && a[j] <= a[j - 1]) swap(a[ -- j], a[j]);
    }
    for (int i = 1; i <= n; i ++ )
        cout << a[i] << ' ';
}

Code

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 5e4 + 10;

int n, m;
int cnt[N];
int top_k[11];

int main()
{
    
       
    // 用堆维护 k 个数,堆常数比较大
    // 动态维护一个有序序列
    // 维护一个长度为 k 的序列,新序列前 k 大的数要么为序列中原本前 k 大的数,要么是新加上的数
    // 时间复杂度为 nklogk
    // 如果想让插入一个数有序使用插入排序
    scanf("%d%d", &n, &m);

    int k = 0;  // k 表示当前 top_k 中有多少个元素
    for (int i = 0; i < n; i ++ )
    {
    
    
        int id;
        scanf("%d", &id);
        if (i)
        {
    
    
            printf("%d:", id);
            for (int j = 0; j < k; j ++ ) printf(" %d", top_k[j]);  // 输出前k个数
            puts("");
        }
        // 如果已经出现在前 k 个中了,就不需要再管了
        cnt[id] ++ ; 
        bool exists = false;
        for (int j = 0; j < k; j ++ )
            if (top_k[j] == id) 
            {
    
    
                exists = true;
                break;
            }
        if (!exists) top_k[k ++ ] = id;
        sort(top_k, top_k + k, [](int x, int y) -> int {
    
    
            if (cnt[x] != cnt[y]) return cnt[x] > cnt[y];
            return x < y;
        });
        
        k = min(k, m);  // 如果超过 m 个,只取前 m 个
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/geraltofrivia123/article/details/121271248