CodeChef:Devasena(数论)

子集GCD积问题
本文探讨了一道有趣的数学编程问题:给定N个整数,求所有可能子集的GCD(最大公约数)之积,并提供了一个高效的解决方案。

All submissions for this problem are available.

Devasena was the princess of an unknown kingdom (we'll all know which one, in Baahubali 2 ;) ), and her father arranged for a Swayamvara to get her married. He gave all of them a question, and the question was so hard that nobody was able to answer it (Yes you guessed it right, both Baahubali and Bhallaladeva were not present there for the Swayamvara). We all know that Amarendra Baahubali married her later and as a consequence of so many things, she was imprisoned for 25 years. Who knows, if someone else had answered the question that day, then she would have got married to him and things could have been different. Phew! But the bad part, we wouldn't have had the story of Baahubali. :)

Although everything is history now, recently archaeologists discovered the secret question that was asked at the Swayamvara, and you think - "Well, it's such a simple question. I could use a computer to solve it!". The question goes as follows:

You are given N integers (not necessarily distinct) => A1, A2, A3, ..., AN. There are 2Npossible subsets (including the empty subset). The GCD of a subset is defined as the greatest common divisor of all the integers in that subset. You need to find the product of the GCDs of all the 2N possible subsets you can construct from A. Since the answer can be large, you need to output the answer modulo 1000000007. Do you think you can solve this question?

Note: The greatest common divisor of an empty subset is 1. To know more about the definition of greatest common divisor, check here.

Input

The first line of input consists of a single integer T denoting the number of test cases. The description of T test cases follow. The first line of each test case consists of a single integer N. The second line of each test case consists of N space separated integers A1, A2, ..., AN

Output

For each test case, output an single integer on a separate line denoting the answer for that test case. Note that you need to output all the values modulo 1000000007 (109 + 7).

Constraints

  • 1 ≤ T ≤ 30
  • 1 ≤ N ≤ 105
  • 1 ≤ Ai ≤ 105

Example

Input:
3
1
1
2
1 2
3
1 2 2

Output:
1
2
8

Explanation

For the first test caseN = 1, and A = [1]. There are 2 possible subsets => {}, {1} and both have a gcd of 1. Hence, the answer is 1 * 1 = 1.

For the second test caseN = 2, and A = [1, 2]. There are 4 possible subsets => {}, {1}, {2}, {1, 2}, having a gcd of 1, 1, 2 and 1 respectively. Hence, the answer is 1 * 1 * 2 * 1 = 2.

For the third test caseN = 3, and A = [1, 2, 2]. There are 8 possible subsets => {}, {1}, {2}, {2}, {1, 2}, {2, 2}, {1, 2}, {1, 2, 2}, having a gcd of 1, 1, 2, 2, 1, 2, 1, 1. Hence, the answer is 1 * 1 * 2 * 2 * 1 * 2 * 1 * 1 = 8.

题意:给N个数,计算每个子集的gcd之积。

思路:考虑每个数对答案的贡献,a[i]表示gcd为i的子集数,a[i] = a[i*2]-a[i*3]-a[i*4]......,ans *= qmod(i,a[i]),先O(nlogn)预处理因子,再O(nlogn)计算答案,根据费马小定理,计算a[i]时要%(mod-1)。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+7;
const int maxn = 1e5+30;
int a[maxn];
vector<int>fac[maxn];
void init()
{
    for(int i=1; i<=100000; ++i)
        for(int j=i; j<=100000; j+=i)
            fac[j].push_back(i);
}
LL qmod(LL x, LL y, LL mo)
{
    LL ans = 1;
    for(;y;y>>=1)
    {
        if(y&1) ans = ans*x%mo;
        x = x*x%mo;
    }
    return ans;
}
int main()
{
    init();
    int T, n, m;
    scanf("%d",&T);
    while(T--)
    {
        LL ans = 1;
        int imax = 0;
        scanf("%d",&n);
        memset(a, 0, sizeof(a));
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&m);
            imax = max(imax, m);
            for(auto j : fac[m])
                ++a[j];
        }
        for(int i=imax; i>0; --i)
        {
            if(!a[i]) continue;
            LL num = (qmod(2, a[i], mod-1)-2+mod)%(mod-1);
            for(int j=i+i; j<=imax; j+=i)
            {
                num -= a[j];
                if(num < 0) num = num+mod-1;
            }
            a[i] = num;
            num = qmod(i, num, mod);
            ans = ans*num%mod;
        }
        printf("%lld\n",ans);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值