1010: QAQ的序列价值
时间限制: 3 Sec 内存限制: 128 MB提交: 60 解决: 13
[ 提交][ 状态][ 讨论版]
题目描述
QAQ有一个序列,元素个数有 N N个。
他认为一个序列的价值的是:该序列中不同元素之和。
比如说:序列 (1,1,2,2) (1,1,2,2)价值为 3 3。
现在QAQ想知道所有子序列的价值之和。输入
每组数据占两行,第一行输入一个整数 N N,代表序列元素个数。
接下来一行输入 N N个整数 a[] a[]。
注: 1<=T<=10000,1<=N<=50,1<=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个子序列:
(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)。价值之和为
204
204。
来源
题解(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;
}