HPU 1010: QAQ的序列价值 【状态压缩】

1010: QAQ的序列价值

时间限制: 3 Sec   内存限制: 128 MB
提交: 60   解决: 13
[ 提交][ 状态][ 讨论版]

题目描述

QAQ有一个序列,元素个数有 N N个。

他认为一个序列的价值的是:该序列中不同元素之和。

比如说:序列 (1,1,2,2) (1,1,2,2)价值为 3 3

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

输入

第一行输入一个整数 T T,代表有 T T组测试数据。
每组数据占两行,第一行输入一个整数 N N,代表序列元素个数。
接下来一行输入 N N个整数 a[] a[]

注: 1<=T<=100001<=N<=501<=a[]<=10 1<=T<=10000,1<=N<=50,1<=a[]<=10

输出

对每组测试数据,输出一个整数代表所有子序列价值之和。

结果很大,请对 (109+7) (109+7)取余。

样例输入

2
3
1 1 1
4
10 10 10 8

样例输出

7
204

提示

对于第二组测试数据一共有 15 15个子序列:
101010810,1010,1010,10 (10)、(10)、(10)、(8)、(10,10)、(10,10)、(10,10)、
10,810,810,810,10,810,10,8 (10,8)、(10,8)、(10,8)、(10,10,8)、(10,10,8)、
10,10,810,10,1010,10,10,8 (10,10,8)、(10,10,10)、(10,10,10,8)。价值之和为 204 204

来源

CZY


题解(CZY):

标程应该是这样的,我们用状态压缩的方法记录每个元素的情况。

num[i]i元素出现的次数。

然后枚举每一个状态,共有(1<<10) - 11023种状态。

对于状态S而言,若出现N个元素,那么它们的组合方案就是

cnt = (2^num[i] - 1) * (2^num[i+1] - 1) * ... *(2^num[N] - 1)

状态S的贡献就是出现的不同元素和sum 乘上 组合方案cnt

我们累加贡献即可。

 

注意1 << x的时候,如果爆int的话,要这样写1LL << x


AC代码:

#include<cstdio>
#include<cstring>

typedef long long LL;
const int MOD=1e9+7;
//
//LL Pow_Mod(LL base,LL y,LL MOD)
//{
//     LL ans=1;
//	 while(y) {
//	 	if(y&1) ans=ans*base%MOD;
//	 	y>>=1; base=base*base%MOD;
//	 }	
//	 return ans;
//} 
int main()
{
	int a[15],p[55],T,N;
	p[0]=1;
	for(int i=1;i<=50;++i) p[i]=p[i-1]*2%MOD;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&N);
		memset(a,0,sizeof(a));
		for(int i=0;i<N;++i) {
			int tem;
			scanf("%d",&tem);
			a[tem]++;
		} 
	//	for(int i=1;i<=10;++i) printf("%d\n",a[i]);
		int cnt=(1<<10); LL ans=0;
		for(int i=1;i<cnt;++i) {
			LL times=1,tota=0;
			for(int j=0;j<10;++j) {
				if((i>>j)&1) {
				     times=times*(p[a[j+1]]-1)%MOD;//times溢出 用LL 
					 tota+=j+1; 
				}
			}
			ans=(ans+times*tota%MOD)%MOD; 
		}
		printf("%lld\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值