CF1066EBinary Numbers AND Sum(前缀和,二进制)
Posted ztz11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1066EBinary Numbers AND Sum(前缀和,二进制)相关的知识,希望对你有一定的参考价值。
题目大意
现在,给你两个位数为 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 ",&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(前缀和,二进制)的主要内容,如果未能解决你的问题,请参考以下文章