2025第16届蓝桥杯省赛之研究生组D题最大数字求解
2025第16届蓝桥杯省赛之研究生组D题最大数字求解
- 一、题目描述
- 1.1题干
- 1.2输入范围
- 1.3题目链接
- 二、题目分析
- 三、题目求解
- 3.1求解步骤
- 3.2完整C++代码
- 3.3代码说明
- 3.4代码提交
- 四、小结
一、题目描述
1.1题干
我们有 n 个连续的整数 1,2,3,⋯,n,可以自由排列它们的顺序。
然后,我们把这些数字转换成二进制表示,按照排列顺序拼接形成一个新的二进制数。
我们的目标是让这个二进制数的值最大,并输出这个二进制对应的十进制表示。
输入格式
输入一行包含一个正整数 n。
输出格式
输出一行包含一个整数表示答案。
时间限制:5s,内存限制:512MB。
1.2输入范围
对于 20% 的评测用例,1≤n≤10;
对于 40% 的评测用例,1≤n≤100;
对于 60% 的评测用例,1≤n≤500;
对于 80% 的评测用例,1≤n≤1000;
对于所有评测用例,1≤n≤10000。
1.3题目链接
目前蓝桥杯题库未放出该题,
洛谷平台链接为:https://www.luogu.com.cn/problem/P12186。
二、题目分析
通过阅读题目,首先分析出解题要点有两个,第一是如何将二进制数排序获得最大值,第二是要进行高精度运算。
显然解题的难点是如何进行排序,但是在实际编程过程中发现如何高效进行高精度运算也是想要拿到满分的一个难点。
下面对如何排序进行分析:
- 两个二进制数进行比较,高位首先出现0的数较小,如果一个二进制数都由1组成,那么当然要排在首位;
- 而不都由1组成的数如何排序似乎没有一个清晰的规律,此题形式上与F题01串类似,但无法使用贪心算法;
- 考虑到n是10的4次方量级,那么可以考虑对二进制数两两比较进行排序,使用sort函数,复杂度近似为nlogn,不会超时,而排序判断准则已经在第一条中分析得出。
三、题目求解
3.1求解步骤
步骤如下:
- 首先将1~n的整数化为二进制数,使用字符串存储二进制串;
- 根据高位首先出现0的数较小这一规则,可以使用字符串比较大小来得到组合顺序,s1+s2>s2+s1;
- 获得排序后,将n个二进制串组合成一个大的字符串;
- 使用高精度乘法与加法,将得到的二进制串化为十进制,得到最终输出。
3.2完整C++代码
C++代码如下:
#include<bits/stdc++.h>
using namespace std;const int N1=1e4+10, N2=4*10;
int b[N1];
vector<int> ans1, ans2;
vector<string> vts;
int n;bool comp(int p, int q)
{return vts[p]+vts[q]>vts[q]+vts[p];
}int main()
{cin>>n;for(int i=1; i<=n; i++){b[i]=i-1;int j=i;string tmp="";while(j){tmp=to_string(j&1)+tmp;j>>=1;}vts.push_back(tmp);}sort(b+1, b+n+1, comp);string fs="";for(int i=1; i<=n; i++){fs+=vts[b[i]];}int num1=0; ans1.push_back(1);ans2.push_back(0);//cout<<fs<<'\n';for(int i=fs.size()-1; i>=0; i-=16){int t1=0,t2=1, t3=0;for(int k=i; k>=max(0, i-15); k--){if(fs[k]=='1'){t1+=t2;}t2<<=1;}if(i!=fs.size()-1){for(int k=0; k<ans1.size(); k++){ans1[k]*=(256*256);}}for(int k=0; k<ans1.size(); k++){if(k<ans1.size()-1){ans1[k+1]+=ans1[k]/10;ans1[k]%=10;}}t2=ans1.back();t3=ans1.size();while(t2>=10){ans1.push_back(t2/10);t2/=10;}for(int k=t3-1; k<ans1.size(); k++) ans1[k]%=10;for(int k=0; k<min(ans1.size(), ans2.size()); k++){ans2[k]+=ans1[k]*t1;}if(ans2.size()<ans1.size()){for(int k=ans2.size(); k<ans1.size(); k++) ans2.push_back(ans1[k]*t1);} for(int k=0; k<ans2.size(); k++){if(k<ans2.size()-1){ans2[k+1]+=ans2[k]/10;ans2[k]%=10;}}t2=ans2.back();t3=ans2.size();while(t2>=10){ans2.push_back(t2/10);t2/=10;}for(int k=t3-1; k<ans2.size(); k++) ans2[k]%=10;}for(int k=ans2.size()-1; k>=0; k--) cout<<ans2[k];return 0;
}
3.3代码说明
- 使用vector类型变量vts存储1~n整数转换成的二进制字符串,而后自定义排序规则comp,使用sort函数进行排序;
- 排序后按照顺序拼接所有二进制串存储到fs变量中;
- 为高效计算高精度乘法加法,将二进制串以16位为一组进行拆分计算,类似于256进制计算;
- ans1存储256的幂次,每个元素为10进制数,ans2存储最终的结果,每个元素为10进制数。
之所以以16位为一组进行拆分计算,是因为如果对二进制串逐位进行计算会超时,而以m位为一组进行拆分是一种提高高精度计算效率的算法,此外还有Karatsuba 乘法、多项式优化算法等提高效率的算法,读者可以进行尝试。
3.4代码提交
在洛谷平台上提交上述代码,可以拿到满分,而如果不进行高精度计算优化,只能拿到80%的分数,后面4组测试用例会超时。
四、小结
本题难点首先在于找到正确排序的方法,这一点可能需要一定的技巧和经验。其次需要对高精度计算进行优化,否则只能拿到80%的分数。而如果使用python语言进行解题,那么题目难度会下降,因为python可以直接进行计算,不须考虑高精度的问题。