HPU 1192:Sequence(組合數+二進制選數)

I - Sequence
Time Limit:3000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu

Description

在某個夜黑高的晚上,!!!,原諒我編不下去了


很美吧?放鬆之後,繼續做題吧。

HS(Handsome)的Ocean在紙上寫下$N$個整數,Ocean把它定義爲$O$序列。

Ocean認爲一個序列的價值的是:序列中不同元素個數。

現在他想知道$O$序列中所有子序列的價值之和。


比如說:序列$(1, 1, 2, 2)$價值爲$2$,因爲序列中有$1$和$2$兩個不同元素。 
比如序列$(1, 1, 1)$,共有$7$個子序列,$(1)、(1)、(1)、(1, 1)、(1, 1)、(1, 1)、(1, 1, 1)。$ 價值之和爲$7$。 

Input

第一行輸入一個整數$T$,代表有$T$組測試數據。 
每組數據佔兩行,第一行輸入一個整數$N$,代表序列元素個數。 
接下來一行輸入$N$個整數$a_i$。 

注:$1 <= T <= 10000,1 <= N <= 50,1 <= a_i <= 10。$ 

Output

對每組測試數據,輸出一個結果代表所有子序列價值之和。由於結果會很大,請用$long\,long$(%lld)。

Sample Input

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 

Sample Output

7
15
22
7864320 

題目鏈接

思路:
我的方案: 組合數+用二進制選數

/*
選數原理
比如 :
num[4]={1,3,5,6}
用四個二進制數表示數組對應位選沒選中
例:1001 表示選中num[0]、num[3]兩個數 
*/ 
#include<cstdio>
#include<cstring>
int num[11];//記錄每個數字出現的次數 
long long sum[11];//單個數字的子序列的個數 

long long quickm(long long x,long long y)
{
	long long ans=1;
	while(y>0)
	{
		if(y&1) ans=ans*x;
		y>>=1;
		x*=x;
	}
	return ans;
}

long long solve()
{
	long long ans=0;
	long long ant,temp;
	for(int i=1;i<(1<<10);i++)//選數 
	{
		 ant=0;//記錄所選數的個數 
		 temp=1;//記錄中間結果 
		for(int j=0;j<10;j++)
		{
			if(i&1<<j) 
			{
			ant++;
			temp*=sum[j+1];
			}
		}
		ans+=ant*temp;//價值*方案數
	}
	return ans;
	
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		memset(sum,0,sizeof(sum));
		memset(num,0,sizeof(num));
	for(int i=0;i<n;i++)
	{
		int t;
		scanf("%d",&t);
		num[t]++;
	}
	for(int i=1;i<=10;i++)
	{
		sum[i]=quickm(2,num[i])-1;
	}	
	printf("%lld\n",solve());		
	}
	
	return 0;
}



發佈了40 篇原創文章 · 獲贊 51 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章