zoukankan      html  css  js  c++  java
  • UVALive 7721 K

    /**
    题目:UVALive 7721 K - 2-ME Set
    链接:https://vjudge.net/problem/UVALive-7721
    题意:给定n个数,从中取出一个集合,至少包含两个元素,如果集合内任意两个元素取位与都是0,那么是合法集合。
    如果5个数为{5,2,2,1,4}那么有9种。(5, 2), (5, 2), (2, 1), (2, 1, 4), (2, 4), (2, 1), (2, 1, 4), (2, 4), and (1, 4).
    问最多有多少种合法集合。
    思路:定义dp[i]表示构成集合i的方法数。注意这里的i不是状态压缩那种i,就是纯粹集合内所有的数都满足任意取位与为0,所有数位或起来的。
    因为每个数大小最多为20000,从1到20000取位或发现最大为32767。所以dp数组大小为32770.
    
    dp[i] += dp[j];(j<i,(j&(i-j))==0) 逆序枚举j。
    
    为了优化时间,相同的数自身和自身不可能在同一个集合,所以统一处理。
    然后最终计算结果减去所有的单位集合,即每一个数作为一个集合的情况。
    
    */
    
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef pair<int,int> P;
    typedef long long LL;
    const int N = 2e4+10;
    const int M = 15;
    const int mod = 1e9+7;
    const int INF = 0x3f3f3f3f;
    int a[N], dp[32770], s[N], num[N];
    struct node
    {
        int value, cnt;
    }t[N];
    vector<node> v;
    int main()
    {
        int T, cas = 1, n;
        cin>>T;
        while(T--)
        {
            scanf("%d",&n);
            memset(num, 0, sizeof num);
            for(int i = 1; i <= n; i++){
                scanf("%d",&a[i]);
                num[a[i]]++;
            }
            int m = n;
            int n = 0;
            for(int i = 1; i <= 20000; i++){
                if(num[i]){
                    t[n].cnt = num[i];
                    t[n].value = i;
                    n++;
                }
            }
            memset(dp, 0, sizeof dp);
            dp[0] = 1;
            //v.clear();
            //v.push_back(node{0,1});
            for(int i = 0; i < n; i++){
                if(i==0) s[i] = t[i].value;
                else s[i] = s[i-1]|t[i].value;
            }
            for(int i = 0; i < n; i++){
                for(int j = s[i]; j >= t[i].value; j--){
                    if((t[i].value&(j-t[i].value))==0)
                        dp[j] = (dp[j]+(LL)dp[j-t[i].value]*t[i].cnt%mod)%mod;
                }
            }
            int ans = 0;
            for(int i = 1; i <= s[n-1]; i++) ans = (ans+dp[i])%mod;
            printf("Case #%d: %d
    ",cas++,(ans-m+mod)%mod);
        }
        return 0;
    }
  • 相关阅读:
    【POJ
    【POJ
    【POJ
    【POJ
    【POJ
    【POJ
    【POJ
    【POJ
    NAT
    OSPF与ACL综合实验
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7267202.html
Copyright © 2011-2022 走看看