题目详情
给定一个正整数n,我们把从1到n的数连接起来形成一个数n1,例如n=11,我们得到的n1=1234567891011,然后我们删掉这个数中在偶数位置的数字,得到数字n2(例子中n2=1357901), 我们再删除n2中奇数位置的数字得到数字n3(例子中n3=370),重复上面的删数字过程,直到剩余一个数字,求最后剩余的数字。 (1<=n<=99999)。
这道题我想到了两种解法,一种是简单的双循环,我当时觉得15分的题不会这么简单,联想到之前碰到的极限数据,就否定了这个方案,
之后又想了下面的第二个方法,只要O(logn)的复杂度,这道题居然一次过了.然后我手贱把第一个代码也贴上去,又过了,瞬间就迷茫了...
//双循环版
#include<stdio.h>
#include<string.h>
#define N 99999 * 5
char str[N];
int mark[N];
int remain( int n)
{
int i;
char *p = str + 1;
int len;
int start;
int end;
int kill;
for (i = 1; i <= n; i++)
{
sprintf(p, "%d" , i);
p += strlen(p);
}
len = strlen(str + 1);
start = 1;
end = len;
kill = 2;
memset(mark, 0, sizeof (mark));
while (start < end)
{
int num = 1;
int i;
for (i = start; i <= end; i++)
{
if (len > 1 && mark[i] == 0)
{
if (num == kill)
{
mark[i] = 1;
len--;
}
num = num == 2 ? 1 : 2;
}
}
while (mark[start] == 1)
{
start++;
}
while (mark[end] == 1)
{
end--;
}
kill = kill == 2 ? 1 : 2;
}
return str[end] - '0' ;
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
printf( "%d" ,remain(99999));
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
#include<string.h>
#define N 99999 * 5
char str[N];
int mark[N];
int remain( int n)
{
int i;
char *p = str + 1;
int len;
int start;
int end;
int kill;
for (i = 1; i <= n; i++)
{
sprintf(p, "%d" , i);
p += strlen(p);
}
len = strlen(str + 1);
start = 1;
end = len;
kill = 2;
memset(mark, 0, sizeof (mark));
while (start < end)
{
int num = 1;
int i;
for (i = start; i <= end; i++)
{
if (len > 1 && mark[i] == 0)
{
if (num == kill)
{
mark[i] = 1;
len--;
}
num = num == 2 ? 1 : 2;
}
}
while (mark[start] == 1)
{
start++;
}
while (mark[end] == 1)
{
end--;
}
kill = kill == 2 ? 1 : 2;
}
return str[end] - '0' ;
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
printf( "%d" ,remain(99999));
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
//优化版
#include<stdio.h>
#include<string.h>
#define N 99999 * 5
int remain (int n)
{
int i;
int len;
int start, end;
int jump, kill;
char str[N];
char *p = str + 1;
for(i = 1; i <= n; i++)
{
sprintf(p, "%d", i);
p += strlen(p);
}
len = strlen(str + 1);
start = 1;
end = len;
jump = 1;
kill = 2;
while(len > 2)
{
if(len % 2 == 0 && kill == 2)
{
end -= jump;
len /= 2;
}
else if(len % 2 == 0 && kill == 1)
{
start += jump;
len /= 2;
}
else if(len % 2 == 1 && kill == 1)
{
start += jump;
end -= jump;
len /= 2;
}
else
{
len -= len / 2;
}
kill = kill == 2 ? 1 : 2;
jump *= 2;
}
if(len == 2 && kill == 2)
{
return str[start] - '0';
}
return str[end] - '0';
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
printf("%d",remain(99999));
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。
#include<string.h>
#define N 99999 * 5
int remain (int n)
{
int i;
int len;
int start, end;
int jump, kill;
char str[N];
char *p = str + 1;
for(i = 1; i <= n; i++)
{
sprintf(p, "%d", i);
p += strlen(p);
}
len = strlen(str + 1);
start = 1;
end = len;
jump = 1;
kill = 2;
while(len > 2)
{
if(len % 2 == 0 && kill == 2)
{
end -= jump;
len /= 2;
}
else if(len % 2 == 0 && kill == 1)
{
start += jump;
len /= 2;
}
else if(len % 2 == 1 && kill == 1)
{
start += jump;
end -= jump;
len /= 2;
}
else
{
len -= len / 2;
}
kill = kill == 2 ? 1 : 2;
jump *= 2;
}
if(len == 2 && kill == 2)
{
return str[start] - '0';
}
return str[end] - '0';
}
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
printf("%d",remain(99999));
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。