【题目链接】

ybt 1955:【11NOIP普及组】瑞士轮
OpenJudge NOI 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函数排序,排名相邻的选手比赛,修改分数后继续排序。该算法需要进行rrr次排序,每次排序的复杂度为O(nlogn)O(nlogn)O(nlogn),题目中r能达到50,元素个数为题目中n的二倍,能达到2∗1052*10^52∗105,所以整体复杂度量级为r∗n∗log2n=50∗2∗105∗log2(2∗105)=107(log22+5log210)≤107(log22+5log216)=2.1∗108r*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^8r∗n∗log2​n=50∗2∗105∗log2​(2∗105)=107(log2​2+5log2​10)≤107(log2​2+5log2​16)=2.1∗108,不出意外的话一定会超时的。因此这一直接的思路是不行的。

解法1:合并有序序列(归并)

第一次排序后,排名相邻的两选手之间比赛。胜方加1分,负方加0分。考察各选手得分的规律。
记sis_isi​为第i名选手的分数,siws_{iw}siw​为第i名选手与第i+1名选手比赛中胜者的分数,sils_{il}sil​为败者的分数。
按分数排序后,取任意两组要进行比赛的选手,第iii名与第i+1i+1i+1名比赛,第jjj名与第j+1j+1j+1名比赛,且i+1<ji+1<ji+1<j,那么一定有:si≥si+1≥sj≥sj+1s_i \ge s_{i+1} \ge s_j \ge s_{j+1}si​≥si+1​≥sj​≥sj+1​
现在第iii名与第i+1i+1i+1名进行比赛

  • 如果第iii名选手获胜,则siw=si+1,sil=si+1s_{iw}=s_i+1,s_{il}=s_{i+1}siw​=si​+1,sil​=si+1​。
  • 如果第i+1i+1i+1名选手获胜,则siw=si+1+1,sil=sis_{iw}=s_{i+1}+1,s_{il}=s_{i}siw​=si+1​+1,sil​=si​

第jjj名与第j+1j+1j+1名进行比赛

  • 如果第jjj名选手获胜,则sjw=sj+1,sjl=sj+1s_{jw}=s_j+1,s_{jl}=s_{j+1}sjw​=sj​+1,sjl​=sj+1​。
  • 如果第j+1j+1j+1名选手获胜,则sjw=sj+1+1,sjl=sjs_{jw}=s_{j+1}+1,s_{jl}=s_{j}sjw​=sj+1​+1,sjl​=sj​

可以看出,无论是何种情况,总是有siw≥sjws_{iw}\ge s_{jw}siw​≥sjw​且sil≥sjls_{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∗105=107r*n=50*2*10^5=10^7r∗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;//分数相等 编号小的在前 elsereturn 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++];elsea[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;//分数相等 编号小的在前 elsereturn 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;//分数相等 编号小的在前 elsereturn 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;
}

信息学奥赛一本通 1955:【11NOIP普及组】瑞士轮 | OpenJudge NOI 4.1 4363:瑞士轮 | 洛谷 P1309 [NOIP2011 普及组] 瑞士轮相关推荐

  1. 信息学奥赛一本通 1942:【08NOIP普及组】ISBN号码 | OpenJudge NOI 1.7 29:ISBN号码 | 洛谷 P1055 [NOIP2008 普及组] ISBN 号码

    [题目链接] ybt 1942:[08NOIP普及组]ISBN号码 OpenJudge NOI 1.7 29:ISBN号码 洛谷 P1055 [NOIP2008 普及组] ISBN 号码 [题目考点] ...

  2. 信息学奥赛一本通 1927:【04NOIP普及组】花生采摘 | OpenJudge NOI 1.13 38:花生采摘 | 洛谷 P1086 [NOIP2004 普及组] 花生采摘

    [题目链接] ybt 1927:[04NOIP普及组]花生采摘 OpenJudge NOI 1.13 38:花生采摘 洛谷 P1086 [NOIP2004 普及组] 花生采摘 [题目考点] 1. 模拟 ...

  3. 信息学奥赛一本通 1171:大整数的因子 | OpenJudge NOI 1.6 13:大整数的因子

    [题目链接] ybt 1171:大整数的因子 OpenJudge NOI 1.6 13:大整数的因子 [题目考点] 1. 高精度 考察:高精模低精 高精度计算讲解 [解题思路] 先把参与运算的数字当成 ...

  4. 信息学奥赛一本通 1149:最长单词2 | OpenJudge NOI 1.13 16

    [题目链接] ybt 1149:最长单词2 OpenJudge NOI 1.13 16:最长单词2 [题目考点] 1. 字符串遍历 2. 处理多个字符串 3. while(cin >> - ...

  5. 信息学奥赛一本通 1148:连续出现的字符 | OpenJudge NOI 1.9 11

    [题目链接] ybt 1148:连续出现的字符 OpenJudge NOI 1.9 11:连续出现的字符 [题目考点] 1. 字符串处理 2. 数值统计 [题解代码] 解法1:比较相邻字符 #incl ...

  6. 信息学奥赛一本通 1145:字符串p型编码 | OpenJudge NOI 1.7 31:字符串p型编码

    [题目链接] ybt 1145:字符串p型编码 OpenJudge NOI 1.7 31:字符串p型编码 [题目考点] 1. 字符串处理 [解题思路] 遍历字符串,设置变量curNum表示当前关注的数 ...

  7. 信息学奥赛一本通 1143:最长最短单词 | OpenJudge NOI 1.7 25

    [题目链接] ybt 1143:最长最短单词 OpenJudge NOI 1.7 25:最长最短单词 [题目考点] 1. 字符串处理 [解题思路] 思路1:将字符串分解为多个单词,而后求出各个单词的长 ...

  8. 信息学奥赛一本通 1137:加密的病历单 | OpenJudge NOI 1.7 12

    [题目链接] ybt 1137:加密的病历单 OpenJudge NOI 1.7 12:加密的病历单 [题目考点] 1. 字符串处理 [解题思路] 加密过程有三个工序:循环左移,逆序存储,大小写反转. ...

  9. 信息学奥赛一本通 1121:计算矩阵边缘元素之和 | OpenJudge NOI 1.8 03:计算矩阵边缘元素之和

    [题目链接] ybt 1121:计算矩阵边缘元素之和 OpenJudge NOI 1.8 03:计算矩阵边缘元素之和 [题目考点] 1. 二维数组 [解题思路] 解法1:遍历外圈 一个m行n列的矩阵, ...

最新文章

  1. OpenStack入门修炼之实战--实现阿里云ESC多FLAT网络(21)
  2. DELL通过LCD简单的判别服务器的硬件故障
  3. element隐藏组件滚动条scrollbar使用
  4. Linux入门之系统启动过程及初始化----“翻滚吧,牛宝宝”
  5. 【收藏】HDFS的Java API使用
  6. 把cmakelist转化为Qt Pro文件
  7. crontab 每分钟一次_Celery实现定时任务crontab
  8. 7-2 单源最短路径 (10 分)(思路+详解+邻接表做法)Come Brather!!!!!!!!!!
  9. java 高级泛型_java泛型的高级应用
  10. Safari new Date()
  11. C++ std::pair<,> 是什么怎么用
  12. 如何在 Ubuntu 16.10 的 Unity 8 上运行老式 Xorg 程序
  13. SAP中物料需求计划不考虑库存策略应用案例
  14. 不定时更新-JAVA干货博客
  15. chrome边解析Html边显示,谷歌浏览器插件侧边翻译Edge Translate
  16. NodeBB – 基于 Node.js 的开源论坛系统
  17. web前端期末大作业——基于HTML+CSS+JavaScript实现中国茶文化(30页)
  18. Kaggle网站流量预测任务第一名解决方案:从模型到代码详解时序预测
  19. godoc使用方法介绍
  20. Mock服务的理解和搭建

热门文章

  1. 亲测有效:docker清理Overlay2占用磁盘空间
  2. 使用戴德金分割法从有理数域构造实数域(上)
  3. 如何改gif的背景颜色
  4. 《Java Concurrency in Practice》之原子性(Atomicity)
  5. 使用javaFX的TextField实现简单对话框设计——互联网程序设计基础(1)
  6. centos安装baidupcs
  7. 关于ipad:无法验证服务器身份
  8. c语言常用英语带音标,计算机c语言常见英语单词 带音标.doc
  9. Python学习记录 基于《Python编程 从入门到实践》 Python基础 Python第五课 字典
  10. [LeetCode]704.二分查找及相关题目