题目描述
在某个夜黑月高的晚上,!!!,原谅我编不下去了。
(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;
}