Xtreme8.0 - Play with GCD dp

本文介绍了一个关于GCD(最大公约数)的编程挑战,详细解释了问题背景、输入输出格式及样例,并提供了一种DP(动态规划)解法。代码使用C++实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Play with GCD

题目连接:

https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/play-with-gcd

Description

Minka is very smart kid who recently started learning computer programming.
He learned how to calculate the Greatest Common Divisor (GCD) of given numbers. The GCD http://en.wikipedia.org/wiki/Greatest_common_divisor of k numbers say [n1,n2,n3… nk] is the largest positive integer that divides all these numbers without any remainder. You may find out more about the GCD and the way it is calculated on the Wikipedia website.
Minka has N (1 <= N <= 10^5) balls and there is a number V (1 <= V <= 10^4) written on every ball. Now Minka has to perform Q queries, and in each query he wants to know the number of possible ways he can choose balls out of the N balls, so that GCD of the numbers written on the chosen balls equals to the number X of each query. Although he already knows the answer for each query, he would still like you to check if you can also find answer to his queries.
Since number of ways can be very large, your program should output the number of ways modulus 10^9+7.
Notes:
1) There can be at most 100 distinct numbers written on N balls.
2) By definition, the GCD is only defined for 2 or more numbers. For this problem, however, we will consider that the GCD of a single number may also defined and in such case the GCD of a single number will be equal to the number itself (i.e. the GCD of 2 is 2. Please refer to the explanation of Sample Input 1 for more details).

Input

The first line of each test file contains an integer N (1 <= N <= 10^5) denoting the number of balls.
The next line contains N space separated integer numbers, each one representing the number written on each of the N balls. The ith number (Vi) corresponds to the number written on the ith ball (1 <= Vi <= 10^4).
The third line contains an integer Q (1 <= Q <= 10^4) representing the number of GCD queries that will have to be performed.
Finally, Q lines follow, each one containing an integer X (1 <= X <= 10^4) corresponding to the GCD of each query.

Output

Your program should output the number of ways modulus 10^9+7 that balls can be drawn from the set, so that their GCD equals the number X corresponding to each query.
Note: There is a newline character at the end of the last line of the output.

Sample Input

5
2 3 5 6 6
2
2
5

Sample Output

4
1

Hint

We have 5 balls in the set, labeled with numbers [2, 3, 5, 6, 6] respectively. For the first query (X=2), there are in total 4 (distinct) ways by which we may choose balls so that their GCD equals 2, meaning:

a) {1, 4} (i.e. ball 1 labeled with number 2 and ball 4 labeled with number 6)

b) {1, 5} (i.e. ball 1 labeled with number 2 and ball 5 labeled with number 6)

c) {1, 4, 5} (i.e. ball 1 labeled with number 2, ball 4 labeled with number 6 and ball 5 labeled with number 6)

d) {1} (i.e. ball 1 labeled with number 2 since according to our definition of GCD, the GCD of 2 would equal 2)

Regarding the second query (X=5), there is only one way to choose balls so that their GCD equals 5, which is to choose only ball 3 (labeled with number 5).

题意

给你n个数,问你里面有多少个集合的gcd为x。

最多有100个不同的数。

题解

离散化之后乱dp一波就好了。

代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 100005;
const int mod = 1e9+7;
int p[maxn],dp[10005],n;
int add(int x,int y){
    x+=y;
    if(x>=mod)x-=mod;
    return x;
}
int gcd(int x,int y)
{
    if(y==0)return x;
    return gcd(y,x%y);
}
vector<int>V;
map<int,int> H;
int a[maxn];
long long two[maxn];
int main()
{
    scanf("%d",&n);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&p[i]);
        V.push_back(p[i]);
    }
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    for(int i=0;i<V.size();i++)
        H[V[i]]=i;
    for(int i=1;i<=n;i++)
        a[H[p[i]]]++;
    two[0]=1;
    for(int i=1;i<=n;i++)
        two[i]=two[i-1]*2LL%mod;
    for(int i=0;i<V.size();i++)
    {
        for(int j=1;j<=10000;j++)
            dp[gcd(j,V[i])]=add(dp[gcd(j,V[i])],1LL*(two[a[i]]-1)*dp[j]%mod);
        dp[V[i]]=add(dp[V[i]],(two[a[i]]-1));
    }
    int m;scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x;
        scanf("%d",&x);
        printf("%d\n",dp[x]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值