美团2018年CodeM大赛-初赛B轮 C题低位值

试题链接: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):
输入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

发现对于每个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;
}












猜你喜欢

转载自www.cnblogs.com/weimeiyuer/p/9321566.html
今日推荐