【HPU 1192】: Sequence 【 状态压缩】

题目描述
在某个夜黑月高的晚上,!!!,原谅我编不下去了。
这里写图片描述(http://acm.hpu.edu.cn/upload/image/20161125/20161125214540_41845.jpg)
很美吧?放松之后,继续做题吧。

HS(Handsome)的Ocean在纸上写下NN个整数,Ocean把它定义为OO序列。

Ocean认为一个序列的价值的是:序列中不同元素个数。

现在他想知道OO序列中所有子序列的价值之和。

比如说:序列(1,1,2,2)(1,1,2,2)价值为22,因为序列中有11和22两个不同元素。
比如序列(1,1,1)(1,1,1),共有77个子序列,(1)、(1)、(1)、(1,1)、(1,1)、(1,1)、(1,1,1)。(1)、(1)、(1)、(1,1)、(1,1)、(1,1)、(1,1,1)。价值之和为77。
输入
第一行输入一个整数TT,代表有TT组测试数据。
每组数据占两行,第一行输入一个整数NN,代表序列元素个数。
接下来一行输入NN个整数aiai。

注:1<=T<=10000,1<=N<=50,1<=ai<=10。1<=T<=10000,1<=N<=50,1<=ai<=10。
输出
对每组测试数据,输出一个结果代表所有子序列价值之和。由于结果会很大,请用longlonglonglong(%lld)。
样例输入
4
3
1 1 1
4
1 1 1 1
4
10 10 10 8
20
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
样例输出
7
15
22
7864320
来源
CZY

好早之前都想补这道题,但是无奈不会状态压缩补不动。今天把状态压缩学习了一下,懂了原理之后。看这道题真是so easy 。

50个数字,但是只有10个不同的数字,我们可以用10个二进制数字来表示每个数字的状态.
0000000001 代表第一个数字状态 同时 0000000001的整数形式为1
0000000010 代表第二个数字状态 同时 0000000010的整数形式为2
0000000100 代表第三个数字状态 同时 0000000100的整数形式为 4
。。。。同理
这样就可以用一部分整数来代表 每一个数字的状态
剩下的看代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
#define first fi
#define second se
#define  LL long long
#define fread() freopen("in.txt","r",stdin)
#define fwrite() freopen("out.txt","w",stdout)
#define CLOSE() ios_base::sync_with_stdio(false)

const int MAXN = 1e5+10;
const int MAXM = 10+7;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

int cnt[MAXN];
LL fac[MAXN];
int main(){
    CLOSE();
//  fread();
//  fwrite();
    fac[0]=1;
    for(int i=1;i<=52;i++) fac[i]=fac[i-1]*2;
    int T; scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        memset(cnt,0,sizeof(cnt));
        for(int i=0;i<n;i++){
            int a; scanf("%d",&a);  a--; // 
            cnt[(1<<a)]++; // 这样就可以标记每个数字的个数
        }

        LL ans=0;
        for(int i=0;i<(1<<10);i++){// 我们就可以这样遍历所有的子集情况
             LL temp=1;int nn=0;
             for(int j=0;j<10;j++){// 遍历每一位
                if(i&(1<<j)){
                    LL t=fac[cnt[(1<<j)]]-1;
                    temp*=t; 
                    nn++;
                 }
             }
             ans+=temp*nn; 
        }
        printf("%lld\n",ans);
    } 
    return 0;
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值