当前位置:网站首页>信息学奥赛一本通 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
边栏推荐
- Learning Android from scratch -- baseactivity and activitycollector
- C list field sorting contains numbers and characters
- leetcode008--实现strStr()函数
- Innovation training (10)
- Unity攝像頭跟隨鼠標旋轉
- C# List字段排序含有数字和字符
- Leetcode001 -- returns the subscript of the array element whose sum is target
- General enumeration constant class
- Leetcode004 -- Roman numeral to integer
- Excel uses the functions of replacement, sorting and filling to comprehensively sort out financial data
猜你喜欢
Sword finger offer: the path with a certain value in the binary tree (backtracking)
Use model load_ state_ Attributeerror appears when dict(): 'STR' object has no attribute 'copy‘
Improving 3D object detection with channel wise transformer
Innovation training (IX) integration
Pixel 5 5g unlocking tutorial (including unlocking BL, installing edxposed and root)
解决ValueError: Argument must be a dense tensor: 0 - got shape [198602], but wanted [198602, 16].
View analysis of scenic spots in ArcGIS
Arduino UNO r3+LCD1602+DHT11
Solve valueerror: argument must be a deny tensor: 0 - got shape [198602], but wanted [198602, 16]
AWS eks add cluster user or Iam role
随机推荐
unity摄像机旋转带有滑动效果(自转)
Leetcode008 -- implement strstr() function
Leetcode - > 1 sum of two numbers
C# List字段排序含有数字和字符
Getprop property
Com alibaba. Common methods of fastjson
Last day of 2017
Custom switch control
DIY 一个 Excel 版的子网计算器
redis和mysql区别
Innovation training (V) mid term inspection
Learning Android II from scratch - activity
What is the meaning of load balancing
Progress of innovation training (IV)
selenium模式下切换窗口,抓取数据的实现
Agile practice | agile indicators to improve group predictability
General enumeration constant class
MySQL - data read / write separation, multi instance
Innovation training (10)
Unity RawImage背景无缝连接移动