题意#
定义序列 :
定义函数 .
定义序列 :
求 .
分析#
直接暴力有 .
观察 的形式, 一定可以表示为 .
把二进制形式写出来, 等价于 .
因此,当 时:
把 中二的幂次提出来,设 ,则 需要含有因子 ,即 。
注意: 有特殊情况,若 ,条件恒成立,答案直接就是 ,需要单独判断。
设 为二进制下 的长度 .
考虑枚举上面的 ,由于 位二进制数的取值范围是 ,而 ,因此 。
分两种情况讨论。
当 时#
内的数,最高位都为 .
需要含有因子 ,为了方便表示,设 .
含有 ,这样的数为:
就是最后一项的系数,满足 .
上面共有 项,是等差数列,可以直接求和。
依题意,每个数对答案有 次贡献,还要对 乘上 。
注意: 当 ,即 时,上面的等差数列不存在,答案直接为 。为了方便实现,可以在代码的最前面特判这种情况。
当 时#
和上面类似。不过由于 ,在 当中有一部分数比 大,因此 的计算方法需要改变。
具体地,我们需要满足 ,因此,.
同样地,对这个 项的等差数列求和,乘上 加入贡献。
在这个计算方法中,等差数列的最后一项也被计数了 次,认为其对 这个范围内都有贡献。
然而区间右端点可能 ,所以要减去 次贡献,每次贡献的值是 。
代码#
注意等差数列求和的时候,要用 的逆元代替除法.
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int MAXLEN = 1e7 + 10, mod = 998244353, inv2 = 499122177;
int T, m, c;
char s[MAXLEN];
int pow_2[MAXLEN];
inline int calc(int st, int ed, int x) {//首项、末项、项数
if(x <= 0) return 0;
return (st + ed) * inv2 % mod * x % mod;
}
void solve_0() {
int n = 0;
for(int i = 1; i <= m; i++) n = ((n << 1) + s[i] - '0') % mod;
printf("%lld\n", n * (n + 1) % mod * inv2 % mod);
}
signed main() {
pow_2[0] = 1;
for(int i = 1; i <= 1e7; i++)
pow_2[i] = (pow_2[i - 1] << 1) % mod;
scanf("%lld", &T);
while(T--) {
scanf("%s%lld", (s+1), &c);
if(c % 2 == 0) {
printf("0\n");
continue;
}
if(c - 1 == 0) {
solve_0();
continue;
}
m = strlen(s + 1); c = c - 1;
int p = 0, ans = 0;
while(c != 0 && c % 2 == 0) p++, c /= 2;
for(int t = 0; t <= m - 1; t++) {
int g = max(0ll, t + 1 - p);
//c%2==0的情况在上面处理过了,所以可以像下面这样对等差数列求和
if(t < m - 1) { //t < m - 1时
ans += pow_2[g] * calc(pow_2[t], pow_2[t+1]-pow_2[g], pow_2[t+1-g]-pow_2[t-g]) % mod;
ans %= mod;
} else { //t = m - 1时
//n/(2^g)下取整,也就是二进制下左边的前n-g位的值
int x = 0;
for(int i = 1; i <= m - g; i++)
x = ((x << 1) + s[i] - '0') % mod;
x = (x + mod - pow_2[t - g]);
ans += pow_2[g] * calc(pow_2[t], (pow_2[t] + x * pow_2[g]) % mod, x + 1);
ans %= mod;
int n = 0, r = (pow_2[t] + (x + 1) * pow_2[g] % mod - 1) % mod;
for(int i = 1; i <= m; i++)
n = ((n << 1) + s[i] - '0') % mod;
ans -= (r - n) * (pow_2[t] + x * pow_2[g] % mod) % mod;
ans %= mod;
}
}
ans = (ans + mod) % mod;
printf("%lld\n", ans);
}
return 0;
}
cpp