试题链接:https://www.nowcoder.com/acm/contest/151/C
定义lowbit(x) =x&(-x),即2^(p-1) (其中p为x的二进制表示中,从右向左数第一个1的位置),例如lowbit(10)=2,lowbit(3)=1。
定义函数f(l, r)为(其中0 <= l, r <= n):
![](https://i-blog.csdnimg.cn/blog_migrate/fbbdf2bf6017b75d1622bd7d588c70a5.png)
输入n,求f(l, r)的最大值。
输入描述:
n以二进制形式给出,一行一个二进制01串n,表示l,r的上界。
1 <= 字符串n的长度 <= 20,000
数据保证没有前缀0。
输出描述:
一行一个整数表示答案。
示例1
输入
11
输出
2
说明
二进制串“11”对应的十进制数为“3”
解题思路:
对于公式f(l,r)而言,不断改变r的大小至l>=r,符合公式中条件(2)(3)每算一次会加1,则f(l,r)函数对应的值即为递归调用(2)(3)的次数。
首先,暴力打表将上限n跑到100
![](https://i-blog.csdnimg.cn/blog_migrate/f8f04a61980e78d0a75c7282a1f9b203.png)
发现对于每个n而言,要使f(l,r)最大,l永远为1.
则此时otherwise的条件为 r-lowbit(r)<l<r ,由lowbit(r)的性质,r-lowbit(r)肯定为非负数。则取最大值时,r-lowbit(r)==0
此时再打表,观察发现r-lowbit(r)==0时,要是函数值最大,r 取到 1 2 4 8 16 32...这样2的整数次幂的数
此时便能得知该函数递归方式。对于一个二进制串,每次从右往左找到一个'1',将他置为'0'(条件2)至只有首位为'1'。
接着,将首位'1'置为'0',下一位的后几位全部置为'1'(条件3)
举例:1011101->1011100->1011000->1010000->1000000->111111->...
直至,二进制串变为'0'
由于当进行到类似1000...(条件3)二进制形式下这样的数时,后续都是相同操作,递归次数为 x*(x-1)/2
则,欲使f(l,r)最大,只要找到最接近上限n且'1'最多的二进制串
举例:101111 本身'1'就最多了 110001 当从左往右,第2个'1'置为0,后续置为'1'时,'1'最多,即 101111
具体实现看代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; typedef long long ll; char s[20005]; int main() { while(cin>>s) { int len=strlen(s); if(len==1) { puts("1");continue; } int ans1=0,ans2=0; for(int i=1;i<len;i++) { if(s[i]=='1') ans1++; } if(ans1>1) { for(int i=1;i<len;i++) { if(s[i]=='1') { ans2=len-(i+1); break; } } } cout<<max(ans1,ans2)+len*(len-1)/2<<endl; //本身的'1'的个数,和第2位'1'变'0',后续置'1'的串的'1'的个数比较 } return 0; }