P1583 魔法照片

记录59

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
	int num;
	int w;
}a[20010]={};
bool cmp(node x,node y){
	if(x.w==y.w) return x.num<y.num;
	else return x.w>y.w;
}
int e[15]={};
int main(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=10;i++) cin>>e[i];
	for(int i=1;i<=n;i++){
		cin>>a[i].w;
		a[i].num=i;
	} 
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) a[i].w+=e[(i-1)%10+1];
	sort(a+1,a+n+1,cmp);	
	for(int i=1;i<=k;i++)	cout<<a[i].num<<" ";
	return 0;
} 

题目传送门https://www.luogu.com.cn/problem/P1583


突破点

一共有 n 个人(以 1∼n 编号)向佳佳要照片,而佳佳只能把照片给其中的 k 个人。佳佳按照与他们的关系好坏的程度给每个人赋予了一个初始权值 Wi​。然后将初始权值从大到小进行排序,每人就有了一个序号 Di​(取值同样是 1∼n)。按照这个序号对 10 取模的值将这些人分为 10 类。也就是说定义每个人的类别序号 Ci​ 的值为 (Di​−1)mod10+1,显然类别序号的取值为 1∼10。第 i 类的人将会额外得到 Ei​ 的权值。你需要做的就是求出加上额外权值以后,最终的权值最大的 k 个人,并输出他们的编号。在排序中,如果两人的 Ei​ 相同,编号小的优先。


思路

  1. 存储每个人的权值跟编号 👉 结构体数组
  2. 权值按照题目要求重新赋值
  3. 进行排序,先比较权值,相同再比较编号

代码简析

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
	int num;
	int w;
}a[20010]={};
bool cmp(node x,node y){
	if(x.w==y.w) return x.num<y.num;
	else return x.w>y.w;
}
int e[15]={};
int main(){
	int n,k;
	cin>>n>>k;
	....
} 

struct node{int num;(编号)int w;(权重)}a[20010]={}; (存储每个人的情况)

bool cmp(node x,node y){} 👉 结构体的比较函数

if(x.w==y.w) return x.num<y.num; 👉权重相同的时候才会比较编号,编号由小到大排序

else return x.w>y.w; 👉 按照权重排序,权重由大到小排序

int e[15]={}; 👉 额外得到 Ei​ 的权值

int n,(总人数)k;(得到照片的人)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
	int num;
	int w;
}a[20010]={};
bool cmp(node x,node y){
	if(x.w==y.w) return x.num<y.num;
	else return x.w>y.w;
}
int e[15]={};
int main(){
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=10;i++) cin>>e[i];
	for(int i=1;i<=n;i++){
		cin>>a[i].w;
		a[i].num=i;
	} 
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) a[i].w+=e[(i-1)%10+1];
	sort(a+1,a+n+1,cmp);	
	for(int i=1;i<=k;i++)	cout<<a[i].num<<" ";
	return 0;
} 

先按照权重排序,然后得到新的权重

for(int i=1;i<=n;i++) a[i].w+=e[(i-1)%10+1]; 👉 每个人的类别序号 Ci​ 的值为 (Di​−1)mod10+1

接着按照最终的权重再次排序

sort(a+1,a+n+1,cmp); 👉 最终人数排列的情况

for(int i=1;i<=k;i++) cout<<a[i].num<<" "; 👉 k个得到照片的人


补充

在CSP-J竞赛中,对结构体进行多标准排序是高频操作。以下是两种核心方法竞赛金牌模板


方法一:重载 < 运算符(最推荐)

直接在结构体内部重载 <sort() 会自动使用此规则。

模板:按分数降序,分数相同按ID升序

cpp 复制代码
struct Student {
    int id;
    int score;
    
    // 按分数降序(主标准),分数相同按ID升序(次标准)
    bool operator < (const Student& other) const {
        if (score != other.score) {
            return score > other.score;  // 主标准:降序(用>)
        }
        return id < other.id;            // 次标准:升序(用<)
    }
};

// 使用
vector<Student> v;
sort(v.begin(), v.end());  // 自动调用operator<

多标准扩展(三标准)

cpp 复制代码
struct Node {
    int a, b, c;
    
    // 按a降序,a相同按b升序,b相同按c降序
    bool operator < (const Node& other) const {
        if (a != other.a) return a > other.a;  // a降序
        if (b != other.b) return b < other.b;  // b升序
        return c > other.c;                    // c降序
    }
};

必须记住的规矩

  1. **const 不能漏** :必须是 const` 成员函数

  2. 返回 bool :返回 true 表示"当前对象应排在前面"

  3. 主标准放前面 :用 if 判断主标准,次标准放后面


方法二:Lambda表达式(最灵活)

不修改结构体,外部定义排序规则。

模板(与上面等价)

cpp 复制代码
struct Student {
    int id, score;
};

sort(v.begin(), v.end(), [](const Student& a, const Student& b) {
    if (a.score != b.score) {
        return a.score > b.score;  // 主标准:分数降序
    }
    return a.id < b.id;            // 次标准:ID升序
});

Lambda优势:多规则复用

cpp 复制代码
// 规则1:按分数降序
auto cmp1 = [](const Student& a, const Student& b) {
    return a.score > b.score;
};

// 规则2:按ID升序
auto cmp2 = [](const Student& a, const Student& b) {
    return a.id < b.id;
};

sort(v.begin(), v.end(), cmp1);  // 按分数排
sort(v.begin(), v.end(), cmp2);  // 再按ID排

三、竞赛金牌模板(背下来)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

struct Node {
    int a, b, c;
    
    // 万能三标准排序(降序→升序→降序)
    bool operator < (const Node& other) const {
        if (a != other.a) return a > other.a;  // a降序
        if (b != other.b) return b < other.b;  // b升序
        return c > other.c;                    // c降序
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    vector<Node> v;
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> v[i].a >> v[i].b >> v[i].c;
    }
    
    // 一次排序搞定
    sort(v.begin(), v.end());
    
    // 输出
    for (auto &x : v) {
        cout << x.a << " " << x.b << " " << x.c << "\n";
    }
    return 0;
}

四、常见错误与调试

错误代码 结果 正确写法
bool operator < (Student other) ❌ 编译错误 bool operator < (const Student& other) const
return a.score > b.score; ❌ 漏次标准 if (a.score != b.score) return a.score > b.score;
return score > other.score && id > other.id; ❌ 逻辑错误 if分主次,不能&&
sort(v.begin(), v.end(), cmp); ❌ cmp未定义 auto cmp = [](...){...};

五、一句话总结

CSP-J结构体多标准排序 = 重载<运算符 + 主标准if判断 + 次标准else返回 + 必须加const,Lambda更灵活但代码稍长。

相关推荐
liulilittle8 小时前
XDP VNP虚拟以太网关(章节:一)
linux·服务器·开发语言·网络·c++·通信·xdp
Ralph_Y8 小时前
多重继承与虚继承
开发语言·c++
罗湖老棍子8 小时前
【例4-6】香甜的黄油(信息学奥赛一本通- P1345)
算法·图论·dijkstra·floyd·最短路算法·bellman ford
不染尘.8 小时前
进程切换和线程调度
linux·数据结构·windows·缓存
bkspiderx8 小时前
C++虚析构函数:多态场景下的资源安全保障
c++·析构函数·虚函数表·虚析构函数
jghhh018 小时前
基于C#实现与三菱FX系列PLC串口通信
开发语言·算法·c#·信息与通信
ada7_8 小时前
LeetCode(python)22.括号生成
开发语言·数据结构·python·算法·leetcode·职场和发展
曹轲恒8 小时前
JVM之垃圾回收算法(GC)
jvm·算法
YuTaoShao8 小时前
【LeetCode 每日一题】1161. 最大层内元素和——BFS
算法·leetcode·宽度优先
White_Can9 小时前
《C++11:列表初始化》
c语言·开发语言·c++·vscode·stl