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

1010: QAQ的序列价值

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

题目描述

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

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

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

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

输入

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

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

输出

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

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

样例输入

2
3
1 1 1
4
10 10 10 8

样例输出

7
204

提示

对于第二组测试数据一共有1515个子序列:
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)。价值之和为204204

来源

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
#include

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>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;
}


你可能感兴趣的:(组合,状压)