1010: QAQ的序列價值
時間限制: 3 Sec 內存限制: 128 MB提交: 60 解決: 13
[提交][狀態][討論版]
題目描述
QAQ有一個序列,元素個數有NN個。
他認爲一個序列的價值的是:該序列中不同元素之和。
比如說:序列(1,1,2,2)(1,1,2,2)價值爲33。
現在QAQ想知道所有子序列的價值之和。輸入
每組數據佔兩行,第一行輸入一個整數NN,代表序列元素個數。
接下來一行輸入NN個整數a[]a[]。
注:1<=T<=10000,1<=N<=50,1<=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個子序列:
(10)、(10)、(10)、(8)、(10,10)、(10,10)、(10,10)、(10)、(10)、(10)、(8)、(10,10)、(10,10)、(10,10)、
(10,8)、(10,8)、(10,8)、(10,10,8)、(10,10,8)、(10,8)、(10,8)、(10,8)、(10,10,8)、(10,10,8)、
(10,10,8)、(10,10,10)、(10,10,10,8)(10,10,8)、(10,10,10)、(10,10,10,8)。價值之和爲204204。
來源
題解(CZY):
標程應該是這樣的,我們用狀態壓縮的方法記錄每個元素的情況。
記num[i]是i元素出現的次數。
然後枚舉每一個狀態,共有(1<<10) - 1共1023種狀態。
對於狀態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;
}