UVa 11124 Troubles for Modern Days Problemsetters
2026/9/5 23:50:30 网站建设 项目流程

题目描述

给定一个最多包含1 000 0001\,000\,0001000000个数字的列表,顺序任意,求该列表按非降序排序后第iii个元素的值。为了避免输入数据量过大导致I/O\texttt{I/O}I/O成为性能瓶颈,题目要求参赛者根据给定的三种列表命令动态生成数据。

三种列表命令如下:

  1. NList\texttt{NList}NList:普通列表。格式为NList(n,a1,a2,…,an)\texttt{NList}(n, a_1, a_2, \dots, a_n)NList(n,a1,a2,,an),表示直接给出nnn个元素的值。

  2. IList\texttt{IList}IList:递增列表。格式为IList(n,s,i)\texttt{IList}(n, s, i)IList(n,s,i),表示生成nnn个元素,首项为sss,公差为iiiiii可为正、负或零),即第kkk个元素为s+(k−1)⋅is + (k-1) \cdot is+(k1)i

  3. RList\texttt{RList}RList:随机列表。格式为RList(n,l,h,s)\texttt{RList}(n, l, h, s)RList(n,l,h,s),表示生成nnn个随机数,范围在[l,h][l, h][l,h]之间,使用给定的种子sss和如下随机数生成器:

    • 每次迭代:seed←(seed×17+11) mod 232\textit{seed} \gets (\textit{seed} \times 17 + 11) \bmod 2^{32}seed(seed×17+11)mod232
    • 生成的随机数为l+(seed mod (h−l+1))l + (\textit{seed} \bmod (h - l + 1))l+(seedmod(hl+1))

多个列表命令可以通过+连接,生成一个拼接后的完整列表。所有生成的数字均为323232位有符号整数。输入保证总数字个数在1111 000 0001\,000\,0001000000之间,且每行命令数不超过323232,行长度不超过100010001000字符。

输入格式

输入包含多个测试用例,每个用例占两行:

  • 第一行一个整数iii1≤i≤1 \le i \le1i列表总长度),表示排序后要找的第iii个元素(索引从111开始)。
  • 第二行一个字符串,由若干个列表命令通过+连接而成,不含空格。

输入以单独一行0结束。

输出格式

对于每个测试用例,输出一行,格式为Case X: Y,其中XXX为用例编号(从111开始),YYY为所求的第iii个元素。

样例

输入

4 NList(10,-9,6,-4,-3,6,501,7,6,6,-10000) 13 IList(5,0,1)+IList(3,6,0)+IList(5,5,-1) 1 IList(1000000,-90,0) 123456 RList(1000000,-2000000000,2000000000,0) 200000 IList(50001,-25000,1)+RList(500000,-25000,25000,3333333333)+NList(4,0,0,0,0) 0

输出

Case 1: -3 Case 2: 6 Case 3: -90 Case 4: -1735543272 Case 5: -6808

题目分析

本题的核心挑战在于高效地找到大规模无序数组中的第iii小元素。直接生成所有数字并完整排序的时间复杂度为O(nlog⁡n)O(n \log n)O(nlogn),对于n=106n = 10^6n=106在时限内通常是可行的,但题目特别提示需要“高效的算法”,因此更优的选择是使用快速选择算法。

快速选择(nth_element\texttt{nth\_element}nth_element)是快速排序的变体,能够在期望线性时间O(n)O(n)O(n)内找到第iii小的元素,而无需对全数组排序。C++\texttt{C++}C++标准库中的std::nth_element正是这一算法的实现,它部分重排数组,使得第iii个位置上的元素就是排序后该位置应有的元素,且其左侧元素都不大于它,右侧元素都不小于它。

另一个需要关注的点是数据生成。由于输入以字符串形式给出,且命令数不超过323232,总长度不超过100010001000字符,我们可以直接解析每个命令并实时生成数字存入数组。解析时需注意:

  • 命令名(NListIListRList)和参数之间没有空格;
  • 参数用逗号分隔;
  • 生成随机数时必须使用646464位整数(如long long),防止乘法溢出,同时取模时范围h - l + 1可能超过323232位有符号范围,也需用646464位处理。

解题思路

步骤一:解析输入命令

对于每个测试用例,读入索引iii和一行命令字符串。由于命令间用+分隔,我们按+分割得到每个独立的命令子串。

对每个命令子串:

  • 找到左括号(和右括号)的位置;
  • 提取括号内的参数部分;
  • 将参数中的逗号,替换为空格,方便使用stringstream读取;
  • 根据命令前缀(NListIListRList)分别处理。

步骤二:生成数字

  • NList\texttt{NList}NList:第一个参数为nnn,随后读取nnn个整数,依次存入数组。
  • IList\texttt{IList}IList:读取nnnsssiii,循环nnn次,每次计算s+k⋅is + k \cdot is+ki并存入数组。注意kkk可能很大(最多10610^6106),但乘积仍可用646464位安全计算。
  • RList\texttt{RList}RList:读取nnnlllhhhsss。种子sss323232位无符号整数,但输入可能以十进制给出,应读入为unsigned long long再截断为unsigned int。每次迭代:
    • seed = (seed * 17 + 11) & 0xFFFFFFFFULL
    • 生成值l + (seed % (h - l + 1)),由于h - l + 1可能超过int范围,需用long long计算。

步骤三:查找第iii小元素

将所有生成的数字存入vector<int>后,调用nth_element(nums.begin(), nums.begin() + i - 1, nums.end()),此时nums[i-1]即为答案。该函数的时间复杂度为线性期望。

复杂度分析

  • 时间复杂度:解析和生成数字O(n)O(n)O(n),快速选择O(n)O(n)O(n)期望,总复杂度O(n)O(n)O(n)
  • 空间复杂度:存储所有数字O(n)O(n)O(n)n≤106n \le 10^6n106,内存可接受。

代码实现

// Troubles for Modern Days Problemsetters// UVa ID: 11124// Verdict: Accepted// Submission Date: 2026-06-21// UVa Run Time: 0.100s//// 版权所有(C)2026,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;// 解析一行命令,生成所有数字并追加到 nums 中voidparseAndGenerate(conststring&line,vector<int>&nums){size_t pos=0;while(pos<line.size()){size_t plus=line.find('+',pos);// 查找命令分隔符string cmd=line.substr(pos,plus-pos);// 提取单个命令size_t lp=cmd.find('('),rp=cmd.find(')',lp);string args=cmd.substr(lp+1,rp-lp-1);// 括号内的参数列表for(char&c:args)if(c==',')c=' ';// 逗号转空格便于流读取stringstreamss(args);if(cmd.find("NList")==0){intn;ss>>n;for(intk=0;k<n;++k){intval;ss>>val;nums.push_back(val);}}elseif(cmd.find("IList")==0){intn;longlongs,inc;ss>>n>>s>>inc;for(intk=0;k<n;++k)nums.push_back((int)(s+inc*k));}elseif(cmd.find("RList")==0){intn;longlongl,h;unsignedlonglongseed;ss>>n>>l>>h>>seed;unsignedintseed32=(unsignedint)(seed&0xFFFFFFFFULL);longlongrange=h-l+1;// 可能大于 2^31,用 long longfor(intk=0;k<n;++k){seed32=(unsignedint)((seed32*17ULL+11ULL)&0xFFFFFFFFULL);nums.push_back((int)(l+(seed32%range)));}}pos=(plus==string::npos)?line.size():plus+1;}}intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);inti,caseNo=1;string line;while(cin>>i){if(i==0)break;getline(cin,line);// 消耗第一行末尾的换行符getline(cin,line);// 读取实际的命令行vector<int>nums;nums.reserve(1000000);parseAndGenerate(line,nums);nth_element(nums.begin(),nums.begin()+i-1,nums.end());cout<<"Case "<<caseNo++<<": "<<nums[i-1]<<"\n";}return0;}

总结

本题巧妙地将“大输入生成”与“选择算法”结合起来,考察了两个关键能力:

  1. 字符串解析与数据生成:需要正确处理三种不同格式的命令,尤其注意随机数生成时的溢出和取模范围;
  2. 高效选择算法:使用nth_element替代完整排序,在期望线性时间内求解,是处理大规模“第kkk小”问题的经典策略。

此外,本题也提醒我们,在竞赛环境中,合理的算法选择(而非盲目排序)往往能显著提升程序性能,而C++\texttt{C++}C++标准库中的高效算法(如nth_element)是实现这一目标的利器。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询