SCAU—计算智能–1142 巡逻的士兵–找规律–logn复杂度【可以改进至O(1)复杂度】
有N个士兵站成一队列, 现在需要选择几个士兵派去侦察。
为了选择合适的士兵, 多次进行如下操作: 如果队列超过三个士兵, 那么去除掉所有站立位置为奇数的士兵,
或者是去除掉所有站立位置为偶数的士兵。直到不超过三个战士,他们将被送去侦察。现要求统计按这样的方法,
总共可能有多少种不同的正好三个士兵去侦察的士兵组合方案。
注: 按上法得到少于三士兵的情况不统计。
1 <= N <= 2的32次方-1
输入格式
有多行(可能有上百行,尽量优化代码),每行一个数字N,最后一行是0
输出格式
对每一行的数字N,输出针对N的方案数
直到没有数字
输入样例
10
4
0
输出样例
2
0
解题思路
常规方法是用递归、分治,但是仔细观察可以发现它是有规律的。
首先列举:
士兵数 | 方案数 | 规律 |
---|---|---|
1 | 0 | 20 |
2 | 0 | 21 |
3 | 1 | (21 +20) |
4 | 0 | 22 |
5 | 1 | + |
6 | 2 | (22 +21) |
7 | 1 | - |
8 | 0 | 23 |
9 | 1 | + |
10 | 2 | + |
11 | 3 | + |
12 | 4 | (23+22) |
13 | 3 | - |
14 | 2 | - |
15 | 1 | - |
16 | 0 | 24 |
17 | 1 | + |
… | … | … |
可以发现规律:任取数n,当n是2正整数幂x时,方案数 t == 0,
然后由0递增,到(2x +2x-1)时,t 取最大,再递减,到2x+1时,减回0.
由此,要找到一个数的方案数,只要找到比它小的的 2最大幂即可得出。
例:
若士兵数 n = 14,比它小的 2最大幂为 23,
判断14 > 23+22,
所以方案数为14 - (23+22) = 2
代码如下
#include<stdio.h>
void th(unsigned long int n)
{
unsigned long int k = n,b=1;
while(k = k>>1)b = b<<1;//找到比n小的 2^最大幂
printf("%d\n",(b + (b>>1)) >= n ? n - b:((b<<1) - n));
/*若n比(2^b +2^(b-1))大时,输出方案数为 2^b+1,否则输出方案数为 n-2^b */
}
int main()
{
unsigned long int n;
scanf("%d",&n);
while(n)
{
th(n);
scanf("%d",&n);
}
return 0;
}
小改进
math.h 内求log的复杂度是o(1)
我代码里,
while(k = k>>1)b = b<<1;//找到比n小的 2^最大幂
这步操作实际上是在求 log2n 并向下取整,可以直接用函数 log(n)达到同样的效果。
因此理论上,这步操作可以是 o(1)级别的。
但这份代码已经是我两年前写的啦,也没办法提交OJ测试了,有兄弟试过的可以在评论区回复哈~