[ICPC2020济南L] Bit Sequence - 数位dp
Description
定义 (f(x)) 表示 (x) 二进制表示的 (1) 的数量。给你n个是0或者1的数,再给你一个 (L),问在区间 ([0,L]) 之间有多少个数 (x) 满足 (∀i∈[0,m−1],f(x+i) mod 2=a_i)
Solution
核心观察是,(x+i) 只会频繁影响 (a[0..6]),对于 (a[7..]) 的部分,最多只会发生一次进位
这次进位的影响,只和第 (7) 位往上连着的 (1) 的个数有关
数位 dp,设 (f[pos][lim][sum][cnt]) 表示从高到低处理到了第 pos 位(低位为 0)此时是否顶格,前面数位的和的奇偶性为 (sum),从第 (pos+1) 位往高走的连续 (1) 的个数的奇偶性为 (cnt)
如果处理到了 (pos<7) 的状态,就转入一个暴力
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a[105], b[105], siz, f[105][2][2][2], m, l;
int par(int x)
{
return __builtin_parity(x);
}
int calc(int lim, int sum, int cnt)
{
int ans = 0;
int up = lim ? l % 128 : 127;
for (int i = 0; i <= up; i++)
{
int flag = 1;
for (int j = 0; j < m && flag; j++)
if ((i + j < 128 && (par(i + j) ^ sum ^ a[j])) || (i + j >= 128 && (par(i + j) ^ sum ^ cnt ^ a[j])))
flag = 0;
ans += flag;
}
return ans;
}
int dfs(int pos, int lim, int sum, int cnt)
{
int &ans = f[pos][lim][sum][cnt];
if (~ans)
return ans;
ans = 0;
if (pos < 7)
ans = calc(lim, sum, cnt);
else
for (int i = 0; i <= (lim ? b[pos] : 1); i++)
ans += dfs(pos - 1, lim && b[pos] == i, sum ^ i, i && (!cnt));
return ans;
}
void generate_b()
{
siz = 0;
int t = l;
while (t)
{
b[siz++] = t & 1;
t /= 2;
}
}
void solve()
{
memset(f, -1, sizeof f);
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
cin >> m >> l;
for (int i = 0; i < m; i++)
cin >> a[i];
generate_b();
cout << dfs(siz - 1, 1, 0, 0) << endl;
}
signed main()
{
int t;
cin >> t;
while (t--)
{
solve();
}
}