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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章