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

相关推荐
嘴贱欠吻!11 小时前
Flutter鸿蒙开发指南(七):轮播图搜索框和导航栏
算法·flutter·图搜索算法
张祥64228890411 小时前
误差理论与测量平差基础笔记十
笔记·算法·机器学习
qq_1927798712 小时前
C++模块化编程指南
开发语言·c++·算法
代码村新手12 小时前
C++-String
开发语言·c++
cici1587413 小时前
大规模MIMO系统中Alamouti预编码的QPSK复用性能MATLAB仿真
算法·matlab·预编码算法
历程里程碑14 小时前
滑动窗口---- 无重复字符的最长子串
java·数据结构·c++·python·算法·leetcode·django
2501_9403152615 小时前
航电oj:首字母变大写
开发语言·c++·算法
lhxcc_fly15 小时前
手撕简易版的智能指针
c++·智能指针实现
CodeByV15 小时前
【算法题】多源BFS
算法
TracyCoder12315 小时前
LeetCode Hot100(18/100)——160. 相交链表
算法·leetcode