// 02.22 13:35-17:00
#include <algorithm>
#include <cstdio>
using namespace std;
struct Student {
int GE, GI, sum, r, id;
int cho[6];
} stu[40010];
struct School {
int quota;
int stuNum; //当前录取人数
int id[40010]; //存储录取了哪些考生
int lastAdmit; //存储上一个录取的考生id,方便破格录取
} sch[110];
bool cmpStu(Student a, Student b) {
if (a.sum != b.sum)
return a.sum > b.sum;
else
return a.GE > b.GE;
}
bool cmpID(int a, int b) {
return stu[a].id < stu[b].id;
}
int main() {
int n, m, k; // n考生人数,m学校个数,k志愿个数
scanf("%d%d%d", &n, &m, &k);
//录入学校信息
for (int i = 0; i < m; i++) {
scanf("%d", &sch[i].quota); // 学校的招生名额
sch[i].stuNum = 0; //当前已招生人数
sch[i].lastAdmit = -1; // -1表示上一个不存在
}
// 录入学生信息
for (int i = 0; i < n; i++) {
stu[i].id = i; //考生id
scanf("%d%d", &stu[i].GE, &stu[i].GI);
stu[i].sum = stu[i].GE + stu[i].GI;
// 录入志愿信息
for (int j = 0; j < k; j++) {
scanf("%d", &stu[i].cho[j]);
}
}
//对学生进行排序
sort(stu, stu + n, cmpStu);
//对学生计算排名,从0开始
for (int i = 0; i < n; i++) {
if (i > 0 && stu[i].sum == stu[i - 1].sum &&
stu[i].GE == stu[i - 1].GE) {
stu[i].r = stu[i - 1].r;
} else {
stu[i].r = i;
}
}
//重要的时刻来啦,我们要开始录取啦啦啦啦啦
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
int choice = stu[i].cho[j]; //当前学生的当前学校id
int num = sch[choice].stuNum; //当前学生的当前学校的已录取人数
int last = sch[choice].lastAdmit; //当前学校的上一个录取人数
// 怎么才能录取呢?
// 条件:当前学生选择的志愿的学校名额没满,或,当前学校录取的上一个学生的排名和当前学生的排名相同
if (num < sch[choice].quota ||
(last != -1 && stu[i].r == stu[last].r)) {
sch[choice].id[num] = i; //录取啦,(^-^)V,将当前考生id插入到该学校的所有编号中
sch[choice].stuNum++; //当前学校的已录取人数++
sch[choice].lastAdmit = i; //当前学校的上一个录取id变了
break; // 当前志愿已录取,不用再看其他志愿了
}
}
}
// 依次输出学校录取的学生编号,放榜啦~~
for (int i = 0; i < m; i++) {
if (sch[i].stuNum > 0) {
sort(sch[i].id, sch[i].id + sch[i].stuNum, cmpID);
for (int j = 0; j < sch[i].stuNum; j++){
printf("%d", stu[sch[i].id[j]].id);
if(j < sch[i].stuNum-1){
printf(" ");
}
}
}
printf("\n");
}
return 0;
}