[CF1329B] Dreamoon Likes Sequences - 计数dp
Description
有两个整数 \(d, m\),找到这样的数列 \(a\) 的数列,满足以下限制条件:
- 数列 \(a\) 的长度为 \(n\),\(n \ge 1\);
- \(1 \le a_i \lt a_2 \lt \cdots \lt a_n \le d\);
- 定义一个长度为 \(n\) 的数组 \(b\):\(b_1 = a_1\),\(\forall i \ge 1, b_i = b_{i - 1} \oplus a_i\),其中 \(\oplus\) 表示二进制异或 (xor)。在构建出 \(b\) 后,应当满足 \(b_1 \lt b_2 \lt \cdots \lt b_{n - 1} \lt b_n\) 的限制条件。
Solution
每个 \(a_i\) 一定比之前的最高位要高,确定了这个最高位以后,低位就可以任意选择,只要保证选择数不超过 \(d\) 即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M = 35;
int d, m;
int f[M][M], pw[M + 1], pwm[M + 1];
void solve()
{
cin >> d >> m;
pw[0] = 1;
pwm[0] = 1;
for (int i = 1; i <= M; i++)
pw[i] = pw[i - 1] * 2, pwm[i] = pwm[i - 1] * 2 % m;
memset(f, 0, sizeof f);
for (int i = 0; i < M; i++)
if (pw[i] <= d)
f[1][i] = min(pw[i], d - pw[i] + 1),
f[1][i] %= m;
for (int i = 2; i < M; i++)
{
for (int j = 1; j < M; j++)
{
for (int k = 0; k < j; k++)
{
if (pw[j + 1] > d)
{
if (d - pw[j] >= 0)
f[i][j] += f[i - 1][k] * ((d - pwm[j] + 1) % m + m) % m;
f[i][j] %= m;
}
else
{
f[i][j] += f[i - 1][k] * pwm[j] % m;
f[i][j] %= m;
}
}
}
}
int ans = 0;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < M; j++)
{
// cout << f[i][j] << " ";
ans += f[i][j];
ans %= m;
}
// cout << endl;
}
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
solve();
}
}