Welcome To HPU Online Judge!
1192: Sequence [组合数学]
时间限制: 3 Sec 内存限制: 128 MB提交: 160 解决: 62
题目描述
在某个夜黑月高的晚上,!!!,原谅我编不下去了。
很美吧?放松之后,继续做题吧。
HS(Handsome)的Ocean在纸上写下 N
序列。
Ocean认为一个序列的价值的是:序列中不同元素个数。
现在他想知道 O
序列中所有子序列的价值之和。
比如序列 (1,1,1) ,共有 7 个子序列, (1)、(1)、(1)、(1,1)、(1,1)、(1,1)、(1,1,1)。 价值之和为 7
。
输入
第一行输入一个整数
T
,代表有
T
组测试数据。每组数据占两行,第一行输入一个整数 N ,代表序列元素个数。
接下来一行输入 N 个整数 ai 。
注: 1<=T<=10000,1<=N<=50,1<=ai<=10。
输出
对每组测试数据,输出一个结果代表所有子序列价值之和。由于结果会很大,请用
longlong
(%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
题意:》》》》
思路:统计每一个数的出现次数,然后用其子集合数乘以选中的个数求和即可(总价值=价值*方案数);
下面附上代码:
/*样例解释 10 10 10 8
10的个数为3,则10所构成的集合数(或者可以理解为方案数)
为2^3-1, 同理
8的方案数为1,那么选数的话共有三种可能(10),(8),(10,8),
其价值分别为10的方案数,8的方案数,10的方案数*8的方案数*2
求和即可*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL a[15],sum[15];//a用来记录每个数出现的次数,sum记录每个数的方案数
int N,T,b;
/*LL Quick_mod(LL a,LL b){//从别的博客上看的算法,可以优化时间和空间复杂度。
LL ans=1;
while(b){
if(b&1) ans*=a;
b>>=1;
a*=a;
}
return ans;
}*/
LL solve(){
LL ans=0;
for(LL i=1;i<(1<<10);i++){
LL ams=1;
LL k=0;
for(LL j=0;j<10;j++){//选数
if(i&(1<<j))
{
k++;//记录的选中的数的个数
ams*=sum[j+1];//记录其每个数的方案数的和
}
}
ans+=ams*k;//总价值=每种可能的方案数*价值的和
}
return ans;
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d",&N);
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
while(N--){
scanf("%d",&b);
a[b]++;
}
for(int i=1;i<=10;i++)
sum[i]=pow(2,a[i])-1;//计算方案数
printf("%lld\n",solve());
}
return 0;
}