poj1019
来源:互联网 发布:黑客破解软件授权 编辑:程序博客网 时间:2024/05/22 07:03
这道题目不难但是很麻烦,而且题意容易误解。一开始我就没有完全搞懂题意,导致错误。最容易出错的地方在超过1位数的数字占用位数不再是1了,而是其数字个数,这也应该不算什么难点,只是容易搞成所有数字都是一位(一时就脑袋蒙了),若所有数字都是1位,那么就简单多了,直接用求和公式k*(1+k)/2,求出S1+S2+……+SK的所有数字个数,然后稍加处理即可。而这里不同数字要按照实际位数计算。不过分析思路还是同上。只是处理起来要麻烦多了。
分析如下:
可以二分查找出小于或等于n(即题目输入的i值)的k,即 S1+S2+……+SK<=n,具体计算方法稍后说明。这里有两种情况。
1)若为相等,那么第n位即为数字K的最后一位,直接输出
2)若小于,那么第n位必定为数字K+1序列数字中的某一位。
情形2)更复杂,也可以分两种情况:
i)当第n位数字为刚好1位数,2位数,……,k位数的结束位时,则必定为9
ii)否则,第n位数字为这些位中某个数的中间一位数字
而第ii)种情况又可以细分为如下两种情况:
iii 1)第n为数字为数字的末尾位,特殊处理
iii 2)否则,一般处理
这里详细介绍一下上面所述的关于如何计算S1+S2+……+Sk的问题。
这里设置两个数字first,和 num 。分别记录K位数的第一个数字和K位数的个数。例如1位数的第一个数字为1,个数为9,2位数第一个数字为10,个数为90,等等。
那么SK的计算方法为求出所有位数小于K数字位数的数字个数与它们各自位数的乘积之和(即位数小于K位数的所数字位数之,利用上面所述的两个数组),
然后加上(K-first[len(K)]+1)* len(K)。依次求出S1,S2,……SK的值,然后相加。
上述过程可以抽象为一个函数。
下面是代码:132K+94MS
#include <stdio.h>#include <stdlib.h> //初始化first与num数组int first[11]={0,1,10,100,1000,10000,100000,1000000,10000000,100000000};int num[11]={0,9,90,900,9000,90000,900000,9000000,90000000,900000000};int Case;__int64 n; // 输入值i__int64 record; bool trag; // 标记量__int64 Get_num(int number){ // S1+S2+S3+……SK求和__int64 pro=0; // 保存结果for(int j=1;j<=number;j++){ // 循环求解SKint i,len=0,temp=j;while(temp>0){ // 求解数字位数len++;temp/=10;}for(i=1;i<len;i++) // 累加比该位数小的所有数字位数之和pro+=num[i]*i;pro+=(j-first[len]+1)*len; // 加上该位数的数字位数之和}return pro; //返回求和结果}int Binary_search(int left,int right){ // 二分查找Sk<=nwhile(left<=right){int mid=(left+right)>>1;if(Get_num(mid)<n)left=mid+1;else if(Get_num(mid)>n)right=mid-1;else{trag=1; //若相等return mid;}}trag=0; // 小于return right; // 注意此处为right而不是left,这样才能保证Sk<n}int main(){scanf("%d",&Case); //case数while(Case--){scanf("%I64d",&n);int Count=Binary_search(1,35000); //经过测试35000是比较合适的数字,保证二分查找的正确性if(trag){ // 若相等则直接输出最后一位数字printf("%d\n",Count%10);continue;} //否则判断是在末尾位还是中间位record=n-Get_num(Count);//printf("%I64d ====\n",record);int pivot=1; while(true){if(record-num[pivot]*pivot>0){ //若还有多余的位数,则继续分解record-=num[pivot]*pivot;pivot++;}else if(record-num[pivot]*pivot<0){ //若没有多余的位数了,则设置标记为0,为中间位trag=0;break;}else{ // 若正好相等,则为结束位,设置标记为1trag=1;break;}}if(trag){ //若为结束位,直接输出9printf("9\n"); continue;}if(record%pivot==0){ // 判断若属于中间数字的最后一位,则特殊处理 int x=first[pivot]+record/pivot-1;printf("%d\n",x%10);continue;} //否则一般处理int x=first[pivot]+record/pivot;int index=pivot-record%pivot+1;pivot=1;while(x>0){if(pivot==index){printf("%d\n",x%10);break;}x/=10;pivot++;}}return 0;}
也给出误解题意的程序(仅作参考)
#include <stdio.h>#include <stdlib.h>#include <math.h>int Case;__int64 n;bool trag;int Binary_search(int left,int right){while(left<=right){int mid=(left+right)>>1;if(n<(mid+1)*mid/2)right=mid-1;else if(n>(mid+1)*mid/2)left=mid+1;else{trag=1;return mid;}}trag=0;return right;}int main(){scanf("%d",&Case);while(Case--){scanf("%I64d",&n);int temp=Binary_search(1,2*int(sqrt(double(n)))+1);if(!trag)printf("%I64d\n",n-(1+temp)*temp/2);elseprintf("%d\n",temp);}return 0;}
- POJ1019
- POJ1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- poj1019
- 双机热备、事物和长事物
- 杭电1215大神的作品
- openstack 虚拟机获取网络ip-记录一下过程
- spfa+栈+邻接表模板POJ3159
- FME 破解
- poj1019
- 如何使用Android MediaStore裁剪大图片
- spfa+队列+邻接表POJ3159
- 有N个标注,把这些标注放在屏幕中间显示
- VS2012 自己 Cocos2dx 的安装配置问题
- eclipse导入android工程@override报错
- 最小生成树邻接表模板
- webView loadData 中文乱码问题
- Cocos2d-x 3.0多线程异步资源加载