题目

1039 Course List for Student 不一样,这题是以课程为主体


解法1

点击查看代码
ream>
#include<vector>
#include<stdio.h>
#include<algorithm>
using namespace std;

struct Course{
    int id;
    vector<string> stdList;
};

int main(){
    int n,k;
    scanf("%d %d",&n,&k);
    vector<Course> vc(k+1);
    
    for(int i=0;i<n;i++){
        string name;
        int total;
        cin>>name>>total;
        for(int j=0;j<total;j++){
            int id;
            scanf("%d",&id);
            vc[id].stdList.push_back(name);
        }
    }
    
    for(int i =1;i<k+1;i++){
        printf("%d %d\n",i,vc[i].stdList.size());
        sort(vc[i].stdList.begin(),vc[i].stdList.end());
        for(int j =0;j<vc[i].stdList.size();j++){
            // cout<<vc[i].stdList[j]<<endl; // 用这个输出会超时
            printf("%s\n",vc[i].stdList[j].c_str());
        }
    }

    return 0;
}

这里我没有存 id,但其实 id 直接等于 i,可以省略 Course 结构

最后输出如果用cout会超时,所以用了printf


优化后

点击查看代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n, k;
    scanf("%d %d", &n, &k);

    // 用 vector 存储课程的学生名单
    vector<vector<string>> courses(k + 1);  

    // 读取学生信息
    for (int i = 0; i < n; i++) {
        char name[5];  // 学生名格式:3个大写字母 + 1位数字 + '\0'
        int total;
        scanf("%s %d", name, &total);
        for (int j = 0; j < total; j++) {
            int id;
            scanf("%d", &id);
            courses[id].push_back(name);
        }
    }

    // 输出课程信息
    for (int i = 1; i <= k; i++) {
        sort(courses[i].begin(), courses[i].end());  // 按字母排序
        printf("%d %d\n", i, (int)courses[i].size());  
        for (const string &name : courses[i]) {
            printf("%s\n", name.c_str());  // 正确转换 string -> C 字符串
        }
    }

    return 0;
}

一些心得

1、scanfprintf 通常比 cincout 更快

2、要用printf打印string,先用string.c_str() 转换为 char*,避免 printf("%s") 打印乱码


拓展

为什么 scanf/printf 更快?

1、scanfprintf 是 C 语言的标准输入输出函数,运行时更轻量

  • scanf 直接在 缓冲区 读取数据,printf 直接输出到 缓冲区,没有额外的封装。

  • cincout 是 C++ 的 流(stream)对象,带有 类型安全检查 和 格式化功能,内部有更复杂的机制,导致速度较慢。

2、cincout 默认同步 stdio,有额外开销

  • cincout 默认 与 C 的 scanfprintf 同步,保证 printfcout 输出顺序一致,但这样会 降低 cin/cout 的性能。

  • 可以通过 关闭同步 来优化:

ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

这样 cincout 的性能就会接近 scanfprintf

3、printf 在批量输出时更高效

  • cout 每次输出数据时都可能 刷新缓冲区,影响性能。

  • printf 只在 \n 或 缓冲区满 时才刷新,避免了多次刷新带来的开销

结论:

  • 默认 cin/cout 最慢
  • 关闭同步后 cin/cout 变快
  • scanf/printf 依然是最快的