OJ:http://acm.hdu.edu.cn/showproblem.php?pid=1597
题目是中文的就不需要翻译了,我自己踩在了一个坑里,好久才爬出来。
我们可以先有一个数组去保存好每一个S串的结束位置,第一个S串结束位置为1,第二个为3,第三个为6,把这些记录下来。
然后我们就可以进行二分的区间查找,找到输入的n是属于哪一个S串中的,然后就能得到答案了
数组的长度不能太大,当然肯定也不能太小,太大的话会导致sum数组中的值溢出,导致二分查找的时候出现异常,根据题目的输入范围,我们要确保sum数组中的最大值尽量的靠在int类型的边界上,去保证二分查找的时候不会超出边界,因为如果mid的值超出了边界,那么l也就会超出边界,就离答案越来越远了。
我一开始就是将MAX的值直接搞成了100000,当然肯定是越界了,哎!!
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 65600
int main()
{
int sum[MAX];
sum[0] = 0;
for(int i=1;i<MAX;i++){
sum[i] = sum[i-1] + i;
}
int k,n;
scanf("%d",&k);
for(;k>0;k--){
scanf("%d",&n);
int l = 0,r = MAX-1,mid,index;
for(;1;){
mid = l + (r - l)/2;
if(sum[mid] < n && sum[mid+1] >= n){
index = mid;
break;
}
if(sum[mid] >= n){
r = mid - 1;
}
if(sum[mid+1] < n){
l = mid + 1;
}
}
index = n - sum[index];
index %= 9;
if(index == 0){
index = 9;
}
printf("%d\n",index);
}
}
第二种代码实现,效率比第一种底一点,而且有点多次一举,只是想测试一下自己写的lower_bound的正确性,测试看来是对的。
这个思路与上面类似,但是也有不一样的地方,这里是先判断输入的n是否刚好是一个字符串的结束位置,如果是的话直接输出,如果不是的话,再找出sum数组中比n大的那个数字的下标,也就是求出了当前n属于哪一个S串,这里就显得有点多次一举了。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 65600
int main()
{
int k,n;
scanf("%d",&k);
int sum[MAX];
memset(sum,0,sizeof(sum));
for(int i=1;i<MAX;i++){
sum[i] = sum[i-1] + i;
}
for(int i=0;i<k;i++){
scanf("%d",&n);
int j;
if((j = find(sum,1,MAX-1,n))!=-1){
j %= 9;
if(j == 0){
j = 9;
}
printf("%d\n",j);
}else{
j = n - sum[lower_bound(sum,1,MAX-1,n)-1];
j %= 9;
if(j == 0){
j = 9;
}
printf("%d\n",j);
}
}
}
int lower_bound(int *f,int l,int r,int find){
for(;l<=r;){
int mid = l + (r - l)/2;
if(f[mid] > find){
r = mid - 1;
}else if(f[mid] < find){
l = mid + 1;
}else{
return l + 1;
}
}
return l;
}
int find(int *f,int l,int r,int find){
for(;l<=r;){
int mid = l + (r - l)/2;
if(f[mid] > find){
r = mid - 1;
}else if(f[mid] < find){
l = mid + 1;
}else{
return mid;
}
}
return -1;
}