[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();
}
}