题意:
给n个不同的数,求所有非空子集的gcd之和
思路:
dp[ i ] 表示 gcd 为 i 的子集数
每读入一个新的数x,可以如果将x与gcd为i的放在一起会导致gcd(x,i)的方案数增加dp[ i ] 种
如果 i = x,那么还会额外多一种方案(只放x)。
因为 较小的gcd(x,i)可能会用到同阶段的较大的 i ,所有操作顺序要从小到大。
代码:
#include<bits/stdc++.h>
const long long mod = 1e8+7;
using namespace std;
const int N = 1005;
int dp[N];
int main()
{
int T;
scanf("%d",&T);
while(T--){
memset(dp,0,sizeof(dp));
int n,x,m = 0;
scanf("%d",&n);
while(n--){
scanf("%d",&x);
m = max(m,x);
for(int i=1;i<=m;i++){
if(i==x)dp[i] = ( ( dp[i]*2 ) + 1 ) % mod;
else if(dp[i]){
int j = __gcd(i,x);
dp[j] = (dp[j] + dp[i]) % mod;
}
}
}long long ans =0;
for(int i=1;i<=m;i++){
ans = (ans + 1LL * i * dp[i] % mod)% mod;
}printf("%I64d\n",ans);
}return 0;
}