CF: *1700
题意:
给定两个很大的二进制数a,b,长度最大2e5,答案每次加上 a&b (位运算),然后b右移一位,直到为0;
问最后答案是多少
思路:
先把两个串都翻转,下标从1开始,便于描述规律:
b这个数每次右移一位,所以现在可以看作这个串往左移动,所以b中的第i位如果为1 ,那他跟a串中的前i个数会进行i次&运算,
所以可以从这个角度来考虑b中的每个1做出的贡献,
对于样例1(从左往右看):b中第一个1跟a做运算得到1010,第二个1跟a运算得到010,第三个1跟a运算得到0,所以和是12
对于样例2(从左往右看):如果a长度<b长度,a高位补零,此时a=01001,b=10101;所以b中1的贡献(二进制表示):1001 + 001 + 1 = 11;
#include<bits/stdc++.h>
using namespace std;
#define out fflush(stdout);
#define fast ios::sync_with_stdio(0),cin.tie(0);
#define FI first
#define SE second
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn = 2e5 + 7;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
int n, m;
char s[maxn], t[maxn];
ll ans = 0;
void swap_() {
int l = 1, r = n;
while(l < r) {
swap(s[l], s[r]);
l++; r--;
}
l = 1, r = m;
while(l < r) {
swap(t[l], t[r]);
l++; r--;
}
}
ll pow_(ll a, int n) {
ll res = 1;
while(n) {
if(n&1) res = (res * a) % mod;
a = (a * a) % mod;
n >>= 1;
}
return res;
}
int main() {
scanf("%d%d", &n, &m);
scanf("%s%s", s+1, t+1);
swap_();
ll cur = 0;
for(int i = 1; i <= m; ++i) {
if(i <= n && s[i] == '1') cur = (cur + pow_(2, i-1)) % mod;
if(t[i] == '1') {
ans = (ans + cur) % mod;
}
}
printf("%lld\n", ans);
return 0;
}