zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    用js实现 全选功能(Gridview)
    图片 加文字水印或者图片水印
    Gridview中RowCommand事件的应用
    图片噪点的产生
    DataList实现折叠效果
    利用Request对象的CurrentExecutionFilePath做分页
    利用分页控件AspNetPager来做数据的分页
    log4Net一些记忆性总结
    彩色验证码
    组织机构设计器窗体基类 代码分析
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9709964.html
Copyright © 2011-2022 走看看