Codeforces 388 D. Fox and Perfect Sets

Posted mangoyang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 388 D. Fox and Perfect Sets相关的知识,希望对你有一定的参考价值。

$ >Codeforces space 388 D. ?Fox?and?Perfect?Sets<$

题目大意 :
定义一个完美的集合 (S) ,当且仅当 (S) 非负非空,且 (forall a, b in S, a ext{ xor } b in S) ,求集合内最大元素不超过 (n) 的完美集合数量

(1 leq n leq 10^9)

解题思路 :

一个完美的集合等价于某个线性基能表示出的所有元素,所以问题转化为对能表示的最大元素 (leq n) 的线性基计数

考虑一个集合的线性基可能有很多种,但是必然存在一种方案使得基上的二进制位表示出来的元素是最大元素,不妨直接对满足这种特征的线性基计数

考虑某一个二进制位如果在基中,那么基中其他位的数都不能有这个位,反之基中所有比它高的位都的数都可以有这个位

如果不考虑 (n) 的限制的话,可以得出一个简单的 (dp[i][j]) 表示从高到低第 (i) 个二进制位,已经选了 (j) 个二进制位作为基的方案数

根据上面推导可以得到 (dp[i][j] = dp[i-1][j] imes 2^j + dp[i-1][j-1]) (选这位为基/不选)

实际上如果有 (n) 的限制的话,是要满足有 (1) 的二进制位组成的二进制数不能超过 (n) ,可以直接套一个数位 (dp)

具体的说,(dp[i][j][0/1]) 表示从高到低第 (i) 个二进制位,已经选了 (j) 个二进制位作为基,当且有 (1) 的位是否是 (n) 在二进制下的前缀

根据当前 (n) 的二进制位是 (0) 还是 (1) 分讨转移即可


/*program by mangoyang*/
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}

#define int ll
const int Mod = 1e9+7;
int s[55], f[55][55][2], len, ans; 
inline void up(int &x, int y){ x = (x + y % Mod) % Mod; }
signed main(){
    int x; read(x); if(!x) s[++len] = 0;
    while(x) s[++len] = x % 2, x /= 2;
    reverse(s + 1, s + len + 1);
    f[0][0][1] = 1;
    for(int i = 1; i <= len; i++)
        for(int j = 0; j <= len; j++){
            if(j) up(f[i][j][0], f[i-1][j-1][0]);
            up(f[i][j][0], f[i-1][j][0] * (1ll << j));
            int x = (j ? (1ll << j - 1) : 1) % Mod;
            int y = (j ? (1ll << j - 1) : 0) % Mod;
            if(s[i] == 0) up(f[i][j][1], f[i-1][j][1] * x);
            else{
                if(j) up(f[i][j][1], f[i-1][j-1][1]);
                up(f[i][j][1], f[i-1][j][1] * y);
                up(f[i][j][0], f[i-1][j][1] * x);
            }
        }
    for(int i = 0; i <= len; i++)
        up(ans, f[len][i][0]), up(ans, f[len][i][1]);
    cout << ans;
    return 0;
}


以上是关于Codeforces 388 D. Fox and Perfect Sets的主要内容,如果未能解决你的问题,请参考以下文章

cf510 D. Fox And Jumping(dp)

CF #228 div1 B. Fox and Minimal path

Codeforces Round #388 (Div. 2)D. Leaving Auction(水题呀?)

网络流(最大流)CodeForces 512C:Fox And Dinner

[Codeforces#510C] Fox And Names

[Codeforces#510D] Fox And Jumping