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更灵活但代码稍长。

相关推荐
imuliuliang18 小时前
关于数据结构在算法设计中的核心作用解析7
算法
code_pgf18 小时前
C++11 / C++14 / C++17 / C++20 新特性总结
c++·c++20
2401_8949155319 小时前
GEO 搜索优化完整源码从零部署:环境配置、集群搭建全流程
开发语言·python·tcp/ip·算法·unity
普通网友20 小时前
共识算法实现:从工作量证明到权益证明的演进
算法·区块链·共识算法
颜x小21 小时前
[C#] C++与c#语法对比
开发语言·c++·c#
ldmd28421 小时前
地图生成算法(噪声篇-Perlin,Simplex,Value noise)
算法·go·地图生成
国科安芯1 天前
FreeRTOS RISC-V 浮点上下文切换移植:在 IAR 工程中完整保存 FPU 寄存器
java·开发语言·单片机·嵌入式硬件·算法·系统架构·risc-v
小陈phd1 天前
集成检索介绍
算法
小poop1 天前
轮转数组:从暴力到最优,一题掌握算法复杂度分析
数据结构·算法·leetcode