P1583 魔法照片

记录59

#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. 进行排序,先比较权值,相同再比较编号

代码简析

#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;(得到照片的人)

#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升序

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<

多标准扩展(三标准)

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表达式(最灵活)

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

模板(与上面等价)

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优势:多规则复用

// 规则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排

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值