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;(权重)}a20010={}; (存储每个人的情况)

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

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

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

int e15={}; 👉 额外得到 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++) ai.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<<ai.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更灵活但代码稍长。

相关推荐
励志不掉头发的内向程序员2 分钟前
【LibreCAD 2D架构】RS_Line创建之后发生了什么?从图形容器到屏幕渲染
开发语言·c++·qt·学习·系统架构
zander2589 分钟前
LeetCode 5. 最长回文子串
算法
hanlin031 小时前
刷题笔记:力扣第84题-柱状图中最大的矩形
笔记·算法·leetcode
青少儿编程课堂2 小时前
威佐夫博弈(双堆取子游戏)解析
c++·python·算法·bfs·信息学竞赛
一个初入编程的小白3 小时前
数据结构:二叉树链式结构的实现
数据结构
辰烨chenye6 小时前
LeetCode Hot 100 题解 · 普通数组篇
算法·leetcode·职场和发展
hqyjzsb9 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye9 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术10 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
sanjiaomao33310 小时前
从论文公式到Python实现:用单元测试校验滑动平均算法
python·算法·单元测试