Problem A 树状数组

给出数x,一直执行x = x and (x+1)-1 直到 x=0 为止 询问这个数执行运算的次数。

这个数以二进制的形式表述出 x = s1 & s2 .... s2 & s3 其中s2字段重复n次 &表示连接符号。

对于$100\%$的数据 $ length(s1),length(s2),length(s3) \leq 10^3 ,n \leq 10^6$

Sol : 这道题目就是求x+1中含有二进制1的个数。

不妨设x=A111...其中A表示一个偶数二进制数,其中后面1的个数可以是任意个。

x+1 = (A+1)000... 所以 x and (x+1) = (A and (A+1))000... = A000...

所以x and (x+1) -1 = (A-1)111... 

可以发现最后的一串1其实是对最后答案没有影响的,所以直接删除即可。

由于每次会破坏且仅破坏A中的一个1。直接求出A中的1的个数即可。

比如 : 1111001100 一次只会破坏最后的0,然后把最低的一个1破坏,--> 1111001011->11110010(消掉末尾所有的1)

这等价于求A=x+1中含有二进制1的个数。

实现细节: 先求出总的1的个数,然后如果数的末尾有连续的1,那么在总的个数中减去即可。

复杂度: $O(T\times length(s1+s2+s3) )$

# pragma GCC optimize(3) 
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=1e5+10;
char s1[N],s2[N],s3[N];
int n;
signed main()
{
    int T; cin>>T;
    while (T--) {
        scanf("%s%s%s",s1,s2,s3);
        scanf("%lld",&n);
        int len1=strlen(s1),len2=strlen(s2),len3=strlen(s3);
        int tot=0;
        for (int i=0;i<len1;i++) if (s1[i]=='1') tot++;
        for (int i=0;i<len2;i++) if (s2[i]=='1') tot+=n;
        for (int i=0;i<len3;i++) if (s3[i]=='1') tot++;
        tot++;
        for (int i=len3-1;i>=0;i--)
         if (s3[i]=='0') goto End;
         else tot--;
        for (int i=len2-1;i>=0;i--)
         if (s2[i]=='0') goto End;
         else tot--;
        tot-=len2*(n-1);
        for (int i=len1-1;i>=0;i--)
         if (s1[i]=='0') goto End;
         else tot--;
        End:printf("%lld\n",tot);   
    }
    return 0;
}
ftree.cpp

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案