您的位置:首页 > 产品设计 > UI/UE

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

2017-10-21 00:11 351 查看
题目描述

在某个夜黑月高的晚上,!!!,原谅我编不下去了。


(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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: