&校内OJ3799
这又是一道打表 找规律的题目
首先这个题目描述就不好懂
(我总疑心这个题目描述有错别字 应该是任意两段吧 还有“左右”是什么意思也许是从左,从右?)
但是这并不能阻挡我们做题
数学上来先打表,于是我们先打个表看看
字典序最小 第一项肯定就是 1了
又要满足条件1,所以第二项就应该是2
然后第三项可以是1
第四项1,2都不能满足条件1,那就是3
···
我们可以得到这个数列
1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 ······
在构造这个数列的过程中,我们可以发现在找后面的数的时候可以借助前面的数来搞
举个栗子
我们已经有了1 2这个数列
首先这个数列本身就满足1、2两个条件
如果我们把它复制一遍
1 2 | 1 2
每个部分都满足1、2两个条件
然而这个整体不满足条件1
由于1 2本身就是在条件1之下字典序最小的数列
所以我们要改动1 2 | 1 2,就只能搞大才能满足条件1,而又要让字典序小,所以,就只把最后那个数给搞大,变成1 2 1 3就满足条件啦
就有点递推的意味了
刚开始有个1->1 2->1 2 1 3->1 2 1 3 1 2 1 4
就是把现有的数列复制一遍 再在最后一个数上+1
然后我们在此基础上来找比较有操作性的规律
因为题目给的是N 并且它的范围还很大 所以我们要研究N这个项数
显而易见的,奇数项时,答案为1
而其它的数,也应该有周期性规律
n
%
2
=
1
=
>
a
[
n
]
=
1
n \% 2 = 1 => a[n] = 1
n%2=1=>a[n]=1
n
%
4
=
2
=
>
a
[
n
]
=
2
n \% 4 = 2 => a[n] = 2
n%4=2=>a[n]=2
n
%
8
=
4
=
>
a
[
n
]
=
3
n \% 8 = 4 => a[n] = 3
n%8=4=>a[n]=3
n
%
16
=
8
=
>
a
[
n
]
=
4
n \% 16 = 8 => a[n] = 4
n%16=8=>a[n]=4
n
%
2
x
=
2
x
−
1
=
>
a
[
n
]
=
x
n \% 2 ^ x = 2 ^ { x - 1 } => a[n] = x
n%2x=2x−1=>a[n]=x
n
≡
2
x
−
1
(
m
o
d
2
x
)
=
>
n
/
(
2
x
−
1
)
≡
1
(
m
o
d
2
)
n ≡2 ^{ x - 1 }( mod \space\space 2 ^ x ) => n / ( 2 ^ { x - 1} )≡1 ( mod \space\space 2 )
n≡2x−1(mod 2x)=>n/(2x−1)≡1(mod 2)
我们就一直对n除以2,直到它为奇数,除以2的次数+1就是答案
由于n的范围较大,我们需要用高精
而对2求余就直接找最后一位就可以了。
#include<cstdio>
#include<cstring>
#define MAXN 1005
using namespace std;
int a[MAXN],ans;
char s[MAXN];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++)
a[i]=s[i]-'0';
while(1)
{
ans++;
if(a[len]%2==1)//整个数求余2和末尾数求余2是一样的
{
printf("%d\n",ans);
return 0;
}
int x=0;
for(int i=1;i<=len;i++)
{
a[i]=(a[i]+x*10);
x=a[i]%2;
a[i]/=2;
}
}
return 0;
}