码迷,mamicode.com
首页 > 其他好文 > 详细

CF1066EBinary Numbers AND Sum(前缀和,二进制)

时间:2018-10-18 00:48:39      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:mes   cal   names   ott   预处理   code   fine   gis   ali   

题目大意

现在,给你两个位数为 n 和 m 的两个二进制数a,b,现在,我们要进行如下操作:

  • 计算a&b
  • 答案累加上一个操作的值
  • bbb右移一位,最后一位直接舍弃

现在,请你算出最终的答案,并输出,答案对998244353取模

输入输出格式:

输入格式:

第一行,两个整数n,m,(1≤n,m≤2×105)

第一行,一个长度为n的二进制数a

第一行,一个长度为m的二进制数b

输出格式:

一行,一个数,表示答案

思路:

因为第一个二进制数不动,第二个在动,所以我们可以通过预处理第一个数来获得答案

因为是与,所以只有两个都是1时才会有答案的贡献

那么,比如说这个例子:

1001
11010

他就会有如下几种情况

01001
11010

1001
1101

1001
0110

1001
0011

1001
0001

我们会发现,第一位的1分别和上面的第一个1和最后一个1异或起来对答案有贡献

所以这个1对答案的贡献是8+1=9

我们把这个规律推广开来

对y中每一个1进行如上操作

即可得出答案

但是,我们会发现答案复杂度是O(n×m)的,过不了

所以我们要预处理

用前缀和跑一遍x即可

复杂度优化到O(m+n)

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rii register int i
#define rij register int j
#define p 998244353
#define int long long
using namespace std;
int a,b;
int x[200005],y[200005],bs[200005],qzh[200005];
void ycl()
{
    bs[0]=1;
    for(rii=1;i<=200002;i++)
    {
        bs[i]=bs[i-1]*2;
        bs[i]%=p;
    }
}
signed main()
{
    scanf("%lld%lld\n",&a,&b);
    for(rii=1;i<=a;i++)
    {
        x[i]=getchar()-0;
    }
    getchar();
    for(rii=1;i<=b;i++)
    {
        y[i]=getchar()-0;
    }
    ycl();
    for(rii=a;i>=1;i--)
    {
        qzh[a-i+1]=qzh[a-i];
        qzh[a-i+1]+=x[i]*bs[a-i];
        qzh[a-i+1]%=p;
    }
    if(b>a)
    {
        for(rii=a+1;i<=b;i++)
        {
            qzh[i]=qzh[i-1];
        }
    }
//  for(rii=1;i<=b;i++)
//  {
//      printf("%d ",qzh[i]);
//  }
    int ans=0;
    for(rii=1;i<=b;i++)
    {
        ans+=y[i]*qzh[b-i+1];
        ans%=p;
    }
    cout<<ans%p;
}

 

CF1066EBinary Numbers AND Sum(前缀和,二进制)

标签:mes   cal   names   ott   预处理   code   fine   gis   ali   

原文地址:https://www.cnblogs.com/ztz11/p/9807576.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!