[题解] P3689 [ZJOI2017] 多项式
此处给出一种在
首先考虑
注:上述转化实际上与次数扩倍的思想基本一致。
考虑如何求出
根据定义,进位数
此时考虑倍增,记
另外,在合并时,若我们仅仅是将
时空复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 263000;
int n, k, str, lim;
char s[20], t[20];
int fl[64][maxn], fr[64][maxn];
ll res[64][maxn], m;
int mat[20][2][2], nx[maxn][2][2], popcnt[maxn];
int mult(int st, bool o1, bool o2)
{
int ans = 0;
for (int i = 0; i < n; i++) ans |= ((popcnt[st & mat[i][o1][o2]] & 1) << i);
return ans;
}
int RE, FL, FR;
void calc(ll nw, int len)
{
RE = FL = FR = 0;
for (int j = 1; j < k && j <= len; j++)
{
ll x = nw & ((1 << j) - 1);
ll y = (str & (((1 << j) - 1) << (k - j))) >> (k - j);
if (x == y) FL |= (1 << j);
}
for (int j = 0; j < k - 1 && j < len; j++)
{
ll x = nw >> (len - j - 1);
ll y = str & ((1 << (j + 1)) - 1);
if (x == y) FR |= (1 << (k - j - 1));
}
for (int j = k; j <= len; j++)
{
ll x = (nw >> (len - j));
x &= ((1 << k) - 1);
if (x == str) RE++;
}
}
ll work(ll x)
{
if (x < k - 1) return 0; x++;
int st = 1;
int rs = 0, ln = 0;
ll nw = 0, ans = 0;
for (int i = lim; ~i; i--)
{
if (!((x >> i) & 1)) st = nx[st][(m >> i) & 1][0];
else
{
int ls = nx[st][(m >> i) & 1][0];
if (i >= 10 || (1 << i) >= k)
{
ans += res[i][ls] + popcnt[rs & fl[i][ls]];
rs = fr[i][ls];
}
else nw |= ((ll)fl[i][ls] << ln), ln += (1 << i);
st = nx[st][(m >> i) & 1][1];
}
}
calc(nw, ln);
return ans + RE + popcnt[rs & FL];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for (int i = 1; i < (1 << 18); i++) popcnt[i] = popcnt[i ^ (i & -i)] + 1;
while (T--)
{
memset(mat, 0, sizeof(mat));
ll l, r; str = 0;
cin >> n >> m >> k >> l >> r >> s >> t;
l = m * n + 1 - l, r = m * n + 1 - r;
swap(l, r);
for (int i = 0; i < k; i++) str |= ((t[i] == '1') << (k - i - 1));
int N = 1 << n;
for (int i = 0; i <= n / 2; i++) swap(s[i], s[n - i]);
for (int c = 0; c < 2; c++)
for (int i = 0; i < n; i++)
for (int j = 0; j <= n; j++)
{
if (s[j] ^ '1') continue;
int nw = i - c + j;
if (nw < 0 || (nw & 1)) continue; nw >>= 1;
mat[i][1][c] |= (1 << nw);
}
for (int c = 0; c < 2; c++)
for (int i = c; i < n; i++)
{
int nw = i - c;
if (nw & 1) continue; nw >>= 1;
mat[i][0][c] |= (1 << nw);
}
for (int st = 0; st < N; st++)
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++) nx[st][i][j] = mult(st, i, j);
lim = 0;
while ((1ll << lim) <= r || (1ll << lim) <= m) lim++;
for (int st = 0; st < N; st++)
{
fl[0][st] = fr[0][st] = (bool)(st & 1);
res[0][st] = 0;
if (k == 1)
{
res[0][st] = (fl[0][st] == str);
fl[0][st] = fr[0][st] = 0;
}
}
for (int i = 1; i <= lim; i++)
{
bool ch = (m >> (i - 1)) & 1;
for (int st = 0; st < N; st++)
{
int ls = nx[st][ch][0], rs = nx[st][ch][1];
if (i <= 4 && (1 << i) < k)
fl[i][st] = fr[i][st] = (fr[i - 1][rs] << (1 << (i - 1))) | fl[i - 1][ls], res[i][st] = 0;
else if (i >= 10 || (1 << i) >= (k << 1))
{
fl[i][st] = fl[i - 1][ls], fr[i][st] = fr[i - 1][rs];
res[i][st] = res[i - 1][ls] + res[i - 1][rs] + popcnt[fr[i - 1][ls] & fl[i - 1][rs]];
}
else
{
int len = 1 << i;
ll nw = ((ll)fr[i - 1][rs] << (1 << (i - 1))) | fl[i - 1][ls];
fl[i][st] = fr[i][st] = res[i][st] = 0;
calc(nw, len); res[i][st] = RE;
fl[i][st] = FL, fr[i][st] = FR;
}
}
}
if (r - l + 1 < k)
{
cout << "0\n";
continue;
}
cout << work(r) - work(l + k - 2) << "\n";
}
return 0;
}