[数位DP][线性基]Codeforces 388D. Fox and Perfect Sets

来源:互联网 发布:apache poi api 编辑:程序博客网 时间:2024/05/22 02:17

Description

一个集合S满足

x,yS,x xor yS
则称这个集合是好的。
所有集合元素小于等于n的集合个数。

Solution

可以从线性基考虑。
按数位从高到低加入。
dpi,j表示考虑前ibit,当前已加入j个基的方案数。
若要加入这个bit那么就直接转移,若不加入相当于要把这个bit给分到已经加入的j个基里面,贡献就是2j
然后枚举异或和转移就好啦。

#include <bits/stdc++.h>using namespace std;const int N = 100;const int MOD = 1000000007;typedef long long ll;int n, m, ans;int dp[N][N][2];inline void Add(int &x, int a) {    x += a; while (x >= MOD) x -= MOD;}int main(void) {    freopen("1.in", "r", stdin);    cin >> n;    dp[32][0][1] = 1;    for (int i = 32; i; i--)        for (int j = 0; j <= 32; j++) {            Add(dp[i - 1][j][0], (1ll << j) * dp[i][j][0] % MOD);            Add(dp[i - 1][j + 1][0], dp[i][j][0]);            long long t0 = j ? (1 << (j - 1)) : 1,                t1 = j ? (1 << (j - 1)) : 0;            if ((n >> (i - 1)) & 1) {                Add(dp[i - 1][j][1], t1 * dp[i][j][1] % MOD);                Add(dp[i - 1][j][0], t0 * dp[i][j][1] % MOD);                Add(dp[i - 1][j + 1][1], dp[i][j][1]);            } else Add(dp[i - 1][j][1], t0 * dp[i][j][1] % MOD);        }    for (int i = 0; i <= 32; i++) {        Add(ans, dp[0][i][1]);        Add(ans, dp[0][i][0]);    }    cout << ans << endl;    return 0;}