当前位置:网站首页>信息学奥赛一本通 1955:【11NOIP普及组】瑞士轮 | OpenJudge 4.1 4363:瑞士轮 | 洛谷 P1309 [NOIP2011 普及组] 瑞士轮
信息学奥赛一本通 1955:【11NOIP普及组】瑞士轮 | OpenJudge 4.1 4363:瑞士轮 | 洛谷 P1309 [NOIP2011 普及组] 瑞士轮
2022-04-23 04:49:00 【君义_noip】
【题目链接】
ybt 1955:【11NOIP普及组】瑞士轮
OpenJudge 4.1 4363:瑞士轮
洛谷 P1309 [NOIP2011 普及组] 瑞士轮
【题目考点】
1. 归并排序
2. stl 排序相关函数
- stl:快速排序:
sort(f1,l1,cmp);
f1: stl容器起始迭代器,或数组第1个元素的指针。
l1:stl容器末尾迭代器,或数组最后一个元素后一个位置的指针。
cmp:比较函数
bool cmp(a,b)
参数a与b的类型必须是容器内元素的类型或数组中元素的类型。
返回值为真,则元素a排在前面。返回值为假,则元素b排在前面。 - stl合并有序序列
merge(f1, l1, f2, l2, r, cmp)
f1, l1:容器1的起始与末尾迭代器,或数组1的第一个与最后一个元素后一个位置的指针。
f2, l2:容器2的起始与末尾迭代器,或数组2的第一个与最后一个元素后一个位置的指针。
r:存放结果的容器的起始迭代器,或存放结果的数组的第一个元素的指针
cmp:比较函数
bool cmp(a,b)
参数a与b的类型必须是容器内元素的类型或数组中元素的类型。
返回值为真,则元素a排在前面。返回值为假,则元素b排在前面。
【解题思路】
直接思路:每次用sort函数排序,排名相邻的选手比赛,修改分数后继续排序。该算法需要进行 r r r次排序,每次排序的复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),题目中r能达到50,元素个数为题目中n的二倍,能达到 2 ∗ 1 0 5 2*10^5 2∗105,所以整体复杂度量级为 r ∗ n ∗ l o g 2 n = 50 ∗ 2 ∗ 1 0 5 ∗ l o g 2 ( 2 ∗ 1 0 5 ) = 1 0 7 ( l o g 2 2 + 5 l o g 2 10 ) ≤ 1 0 7 ( l o g 2 2 + 5 l o g 2 16 ) = 2.1 ∗ 1 0 8 r*n*log_2{n}=50*2*10^5*log_2{(2*10^5)}=10^7(log_2{2}+5log_2{10})\le10^7(log_2{2}+5log_2{16})=2.1*10^8 r∗n∗log2n=50∗2∗105∗log2(2∗105)=107(log22+5log210)≤107(log22+5log216)=2.1∗108,不出意外的话一定会超时的。因此这一直接的思路是不行的。
解法1:合并有序序列(归并)
第一次排序后,排名相邻的两选手之间比赛。胜方加1分,负方加0分。考察各选手得分的规律。
记 s i s_i si为第i名选手的分数, s i w s_{iw} siw为第i名选手与第i+1名选手比赛中胜者的分数, s i l s_{il} sil为败者的分数。
按分数排序后,取任意两组要进行比赛的选手,第 i i i名与第 i + 1 i+1 i+1名比赛,第 j j j名与第 j + 1 j+1 j+1名比赛,且 i + 1 < j i+1<j i+1<j,那么一定有: s i ≥ s i + 1 ≥ s j ≥ s j + 1 s_i \ge s_{i+1} \ge s_j \ge s_{j+1} si≥si+1≥sj≥sj+1
现在第 i i i名与第 i + 1 i+1 i+1名进行比赛
- 如果第 i i i名选手获胜,则 s i w = s i + 1 , s i l = s i + 1 s_{iw}=s_i+1,s_{il}=s_{i+1} siw=si+1,sil=si+1。
- 如果第 i + 1 i+1 i+1名选手获胜,则 s i w = s i + 1 + 1 , s i l = s i s_{iw}=s_{i+1}+1,s_{il}=s_{i} siw=si+1+1,sil=si
第 j j j名与第 j + 1 j+1 j+1名进行比赛
- 如果第 j j j名选手获胜,则 s j w = s j + 1 , s j l = s j + 1 s_{jw}=s_j+1,s_{jl}=s_{j+1} sjw=sj+1,sjl=sj+1。
- 如果第 j + 1 j+1 j+1名选手获胜,则 s j w = s j + 1 + 1 , s j l = s j s_{jw}=s_{j+1}+1,s_{jl}=s_{j} sjw=sj+1+1,sjl=sj
可以看出,无论是何种情况,总是有 s i w ≥ s j w s_{iw}\ge s_{jw} siw≥sjw且 s i l ≥ s j l s_{il}\ge s_{jl} sil≥sjl
即,每次比赛后的获胜方的分数为降序序列,失败方的分数也是降序序列。
考虑到分数相等时比较编号,也会有相同的结论。
接下来就是将两个有序序列合并为一个有序序列的过程。
这一方法在归并排序中有使用,合并有序序列的复杂度为 O ( n ) O(n) O(n)
具体写代码时:
写法1:可以将胜方与败方分别放入两个数组,而后合并有序序列。
写法2:数组下标奇数保存胜方,下标偶数保存败方。
使用该算法完成该题,需要循环r次,每次合并有序数组,复杂度为 O ( r ∗ n ) O(r*n) O(r∗n), r ∗ n = 50 ∗ 2 ∗ 1 0 5 = 1 0 7 r*n=50*2*10^5=10^7 r∗n=50∗2∗105=107,可以通过。
【题解代码】
解法:合并有序序列(归并)
写法1:将胜方与败方分别放入两个数组,而后合并有序序列。
- 手写合并有序序列
#include <bits/stdc++.h>
using namespace std;
#define N 200005
struct Per//选手
{
int i, s, w;//i:编号 s:分数 w:实力
}a[N], w[N], l[N];//a:所有数据 w:胜者组 l:败者组
int n, r, q;
bool cmp(Per a, Per b)
{
if(a.s == b.s)
return a.i < b.i;//分数相等 编号小的在前
else
return a.s > b.s;//分数高的排在前
}
void merge()//合并有序序列w与l
{
int i = 1, j = 1, ai = 1;
while(i <= n && j <= n)
{
if(cmp(w[i], l[j]))//如果w[i]比l[j]优先
a[ai++] = w[i++];
else
a[ai++] = l[j++];
}
while(i <= n)
a[ai++] = w[i++];
while(j <= n)
a[ai++] = l[j++];
}
int main()
{
scanf("%d %d %d", &n, &r, &q);
for(int i = 1; i <= 2*n; ++i)
{
scanf("%d", &a[i].s);
a[i].i = i;//设置编号
}
for(int i = 1; i <= 2*n; ++i)
scanf("%d", &a[i].w);
sort(a+1, a+1+2*n, cmp);
while(r--)
{
for(int i = 1; i <= n; i++)
{
if(a[2*i].w > a[2*i-1].w)//2*i与2*i-1进行一场比赛
{
a[2*i].s++;
w[i] = a[2*i];
l[i] = a[2*i-1];
}
else
{
a[2*i-1].s++;
w[i] = a[2*i-1];
l[i] = a[2*i];
}
}
merge();
}
printf("%d", a[q].i);
return 0;
}
- 使用stl merge函数
#include <bits/stdc++.h>
using namespace std;
#define N 200005
struct Per//选手
{
int i, s, w;//i:编号 s:分数 w:实力
}a[N], w[N], l[N];//a:所有数据 w:胜者组 l:败者组
int n, r, q;
bool cmp(Per a, Per b)
{
if(a.s == b.s)
return a.i < b.i;//分数相等 编号小的在前
else
return a.s > b.s;//分数高的排在前
}
int main()
{
scanf("%d %d %d", &n, &r, &q);
for(int i = 1; i <= 2*n; ++i)
{
scanf("%d", &a[i].s);
a[i].i = i;//设置编号
}
for(int i = 1; i <= 2*n; ++i)
scanf("%d", &a[i].w);
sort(a+1, a+1+2*n, cmp);
while(r--)
{
for(int i = 1; i <= n; i++)
{
if(a[2*i].w > a[2*i-1].w)//2*i与2*i-1进行一场比赛
{
a[2*i].s++;
w[i] = a[2*i];
l[i] = a[2*i-1];
}
else
{
a[2*i-1].s++;
w[i] = a[2*i-1];
l[i] = a[2*i];
}
}
merge(w+1, w+1+n, l+1, l+1+n, a+1, cmp);//stl merge函数 合并有序序列
}
printf("%d", a[q].i);
return 0;
}
写法2:数组下标奇数保存胜方,下标偶数保存败方
#include <bits/stdc++.h>
using namespace std;
#define N 200005
struct Per//选手
{
int i, s, w;//i:编号 s:分数 w:实力
}a[N], t[N];
int n, r, q;
bool cmp(Per a, Per b)
{
if(a.s == b.s)
return a.i < b.i;//分数相等 编号小的在前
else
return a.s > b.s;//分数高的排在前
}
int main()
{
scanf("%d %d %d", &n, &r, &q);
for(int i = 1; i <= 2*n; ++i)
{
scanf("%d", &a[i].s);
a[i].i = i;//设置编号
}
for(int i = 1; i <= 2*n; ++i)
scanf("%d", &a[i].w);
sort(a+1, a+1+2*n, cmp);
while(r--)
{
for(int i = 1; i < 2*n; i += 2)
{
if(a[i].w > a[i+1].w)//i与i+1进行一场比赛
a[i].s++;
else
{
a[i+1].s++;
swap(a[i], a[i+1]);//使胜者的下标为奇数
}
}
int i = 1, j = 2, ti = 1;
while(i <= 2*n-1 && j <= 2*n)//合并下标为奇数的部分与下标为偶数的部分
{
if(cmp(a[i], a[j]))
{
t[ti++] = a[i];
i += 2;
}
else
{
t[ti++] = a[j];
j += 2;
}
}
while(i <= 2*n-1)
{
t[ti++] = a[i];
i += 2;
}
while(j <= 2*n)
{
t[ti++] = a[j];
j += 2;
}
for(int i = 1; i <= 2*n; ++i)
a[i] = t[i];
}
printf("%d", a[q].i);
return 0;
}
版权声明
本文为[君义_noip]所创,转载请带上原文链接,感谢
https://blog.csdn.net/lq1990717/article/details/124356987
边栏推荐
- 【数据库】MySQL基本操作(基操~)
- test
- leetcode005--原地删除数组中的重复元素
- L2-011 play binary tree (build tree + BFS)
- Innovation training (II) task division
- 用LCR表完美测试无线充电系统中的线圈
- C language: Advanced pointer
- Teach you how to build the ruoyi system by Tencent cloud
- Innovation training (XII) reptile
- Summary of MySQL de duplication methods
猜你喜欢

【数据库】MySQL单表查询

用LCR表完美测试无线充电系统中的线圈

Supplement 14: cmake practice project notes (to be continued 4 / 22)

Simply drag objects to the item bar

New terminal play method: script guidance independent of technology stack

Repair of self calibration SPC failure of Tektronix oscilloscope dpo3054

Druid -- JDBC tool class case

泰克示波器DPO3054自校准SPC失败维修

Learning Android from scratch -- Introduction

AWS eks add cluster user or Iam role
随机推荐
【数据库】表的查看、修改和删除
Introduction to raspberry pie 3B - system installation
Recommended scheme of national manufactured electronic components
Innovation training (XII) reptile
Code007 -- determine whether the string in parentheses matches
Experience summary and sharing of the first prize of 2021 National Mathematical Modeling Competition
Perfect test of coil in wireless charging system with LCR meter
Leetcode - > 1 sum of two numbers
Excel protects worksheets and workbooks from damage
Leetcode005 -- delete duplicate elements in the array in place
Leetcode004 -- Roman numeral to integer
POI export message list (including pictures)
unity摄像机旋转带有滑动效果(自转)
Use model load_ state_ Attributeerror appears when dict(): 'STR' object has no attribute 'copy‘
Unity攝像頭跟隨鼠標旋轉
Spark optimization
解决ValueError: Argument must be a dense tensor: 0 - got shape [198602], but wanted [198602, 16].
Innovative practice of short video content understanding and generation technology in meituan
Solve valueerror: argument must be a deny tensor: 0 - got shape [198602], but wanted [198602, 16]
【数据库】MySQL多表查询(一)