/** 题目:Codeforces839D Winter is here 链接:http://codeforces.com/contest/839/problem/D 题意:给定n个数,求所有的最大公约数>1的子集的贡献之和。 一个子集的贡献为最大公约数*子集大小 思路: cnt[i]表示约数为i的数的个数。 ans[i]表示约数为i的所有k的和。 已知ans[i]可以求得贡献为i*ans[i]; cnt[i]个数的长度为(sigma(k))cnt[i]*(2^(cnt[i]-1)); 即所有子集长度的和。 但是其中有些子集的gcd不是等于i。所以要减去。 逆序枚举,ans[i] = cnt[i]*(2^(cnt[i]-1)) - sigma(ans[j]);(j%i==0&&j/i>1) */ #include <cstdio> #include <cstring> #include <algorithm> #include <set> #include <iostream> #include <vector> using namespace std; typedef long long LL; #define ms(x,y) memset(x,y,sizeof x) typedef pair<int, int> P; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const int maxn = 1e6 + 100; int cnt[maxn]; int sum[maxn]; LL ans[maxn]; LL Pow(LL x, int y) { LL p = 1; while (y) { if (y & 1) p = p*x%mod; x = x*x%mod; y >>= 1; } return p; } int main() { int T, cas = 1; int n; while (scanf("%d",&n)==1) { int x, mas = 0; ms(cnt,0); ms(sum,0); ms(ans,0); for(int i = 1; i <= n; i++){ scanf("%d",&x); mas = max(mas,x); sum[x]++; } for(int i = 2; i < maxn; i++){ for(int j = i; j < maxn; j+=i){ cnt[i] += sum[j]; } } LL res = 0; for(int i = mas; i >= 2; i--){ if(cnt[i]==0) continue; LL num = 0; for(int j = 2*i; j <= mas; j+=i){ num = (num+ans[j])%mod; } ans[i] = (cnt[i]*Pow(2,cnt[i]-1)%mod-num+mod)%mod; res = (res+ans[i]*i%mod)%mod; } printf("%I64d ",res); } return 0; }