hdu4675 GCD of Sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675

题意:

  给定一个长度为n的序列a,且 1<=a[i]<=m,求分别有多少个序列b,使得GCD(b[1],b[2],...b[n])=x (1<=x<=m),且正好有k个b[i]!=a[i]。

分析:

  莫比乌斯反演,主要是确定F(x)。

  用F(x)表示gcd为x的倍数的方案数,f(x)表示gcd为x的方案数。

  先考虑F(d)怎么计算。可以把a数组中的数分成两类,第一类是必须对应下标不等的,即a[i]不是d的倍数),其他的就是第二类。

  假设第二类的数量是p,第一类的数量就是n?p,因为要选择k个不同的,第一类必须不同,所以需要在第二类中选择k?n+p个,而b数组中每一个数都有[m/p]种选择。

  所以最终的结果就是F(d)=C(p,k-n+p) ? ( ([m/d]?1)^(k?n+p) )?( [m/d]^(n?p) ),然后暴力计算每一个f(d)就好了。总的复杂度是n(logn)。

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5
  6 using namespace std;
  7 const int maxn=300010;
  8 const long long mod=1e9+7;
  9
 10 int n,m,k;
 11 int a[maxn];
 12 int mu[maxn];
 13 int vis[maxn];
 14 int prime[maxn];
 15 int cnt;
 16 int num[maxn];
 17 long long jie[maxn],ni[maxn];
 18 long long F[maxn];
 19 long long res[maxn];
 20
 21 void init()
 22 {
 23     memset(vis,0,sizeof(vis));
 24     mu[1]=1;
 25     cnt=0;
 26     for(int i=2;i<maxn;i++)
 27     {
 28         if(!vis[i])
 29         {
 30             prime[cnt++]=i;
 31             mu[i]=-1;
 32         }
 33         for(int j=0;j<cnt&&i*prime[j]<maxn;j++)
 34         {
 35             vis[i*prime[j]]=1;
 36             if(i%prime[j])
 37                 mu[i*prime[j]]=-mu[i];
 38             else
 39             {
 40                 mu[i*prime[j]]=0;
 41                 break;
 42             }
 43         }
 44     }
 45 }
 46
 47 long long power(long long a,long long n,long long m)
 48 {
 49     long long ans=1,tmp=a%m;
 50     while(n)
 51     {
 52         if(n&1)
 53             ans=ans*tmp%m;
 54         tmp=tmp*tmp%m;
 55         n=n/2;
 56     }
 57     return ans;
 58 }
 59
 60 long long C(long long n,long long m)
 61 {
 62     if(n==0)
 63         return 1;
 64     return jie[n]*ni[m]%mod*ni[n-m]%mod;
 65 }
 66
 67 int main()
 68 {
 69     init();
 70     ni[0]=1;
 71     jie[0]=1;
 72     for(int i=1;i<maxn;i++)
 73     {
 74         jie[i]=jie[i-1]*i%mod;
 75         ni[i]=power(jie[i],mod-2,mod);
 76     }
 77     while(~scanf("%d%d%d",&n,&m,&k))
 78     {
 79         for(int i=1;i<=n;i++)
 80             scanf("%d",&a[i]);
 81         memset(num,0,sizeof(num));
 82         for(int i=1;i<=n;i++)
 83             num[a[i]]++;
 84         for(int i=1;i<=m;i++)
 85         {
 86             long long p=0;
 87             for(int j=1;j*i<=m;j++)
 88                 p+=num[i*j];
 89             if(k-n+p<0)
 90                 F[i]=0;
 91             else
 92                 F[i]=C(p,k-n+p)*power(m/i-1,k-n+p,mod)%mod*power(m/i,n-p,mod)%mod;
 93         }
 94         for(int i=1;i<=m;i++)
 95         {
 96             long long ans=0;
 97             for(int j=1;i*j<=m;j++)
 98             {
 99                 ans+=mu[j]*F[i*j];
100                 ans=(ans%mod+mod)%mod;
101             }
102             if(i==1)
103                 printf("%lld",ans);
104             else
105                 printf(" %lld",ans);
106         }
107         printf("\n");
108     }
109     return 0;
110 }
时间: 2024-10-11 11:20:52

hdu4675 GCD of Sequence的相关文章

hdu4675 GCD of Sequence 莫比乌斯+组合数学

/** 题目:hdu4675 GCD of Sequence 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4675 题意:给定n个数的a数组,以及m,k: 构造满足1<=bi<=m,和a数组恰好k个位置ai!=bi的b数组. 输出b数组所有数的gcd分别为1~m的数组个数. 思路: f(n)表示gcd==n的数组个数. g(n)表示gcd是n的倍数的数组个数. f(n) = sigma[n|d]mu[d/n]*g(d); 如何求g(d)呢? 如果没

HDU 4675 GCD of Sequence

题意:给N个数,要求改变其中K个数,是改变后的数列GCD为1~M,问对于各个GCD一共有多少组数 解:1.预处理C(n,m),这里用快速幂计算n!,m!,(n-m)!,quick(a,mod-1)=a 2.给定数列中统计i的倍数的个数为temp,如果n-temp>k,那么把k个数换掉,GCD依旧不为i,所以sum[i]=0; 若n-temp<=k,那么先替换掉不是i的倍数的数,一共有(m/i)^(n-temp)种组合,再换掉k-(n-temp)个i的倍数,有(m/i-1)^(k-(n-temp

HDU 4675 GCD of Sequence(莫比乌斯反演 + 打表注意事项)题解

题意: 给出\(M\)和\(a数组\),询问每一个\(d\in[1,M]\),有多少组数组满足:正好修改\(k\)个\(a\)数组里的数使得和原来不同,并且要\(\leq M\),并且\(gcd(a_1,a_2,\dots,a_n)=d\). 思路: 对于每一个\(d\),即求\(f(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)=d\)的对数. 那么假设\(F(d)\):修改\(k\)个后\(gcd(a_1,a_2,\dots,a_n)\)是\(d\)倍数的对数.

HDU4675-GCD of Sequence(数论+组合计数)

GCD of Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 949    Accepted Submission(s): 284 Problem Description Alice is playing a game with Bob. Alice shows N integers a1, a2, -, aN, an

hdu 6025 Coprime Sequence (前后缀GCD)

题目链接:hdu 6025 Coprime Sequence 题意: 给你n个数,让你删掉一个数,使得剩下的数的gcd最大 题解: 先将这一列数的前缀后缀gcd预处理一下. 然后挨着for一下就行了 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 5 const int N=1e5+7; 6 int t,pre[N],suf[N],n,a[N]; 7 8

codeforces 894C - Marco and GCD Sequence - [有关gcd数学题]

题目链接:https://cn.vjudge.net/problem/CodeForces-894C In a dream Marco met an elderly man with a pair of black glasses. The man told him the key to immortality and then disappeared with the wind of time. When he woke up, he only remembered that the key

HDU - 6025 Coprime Sequence(gcd+前缀后缀)

Do you know what is called ``Coprime Sequence''? That is a sequence consists of nnpositive integers, and the GCD (Greatest Common Divisor) of them is equal to 1. ``Coprime Sequence'' is easy to find because of its restriction. But we can try to maxim

G - Mike and gcd problem

G - Mike and gcd problem Mike has a sequence A?=?[a1,?a2,?...,?an] of length n. He considers the sequence B?=?[b1,?b2,?...,?bn] beautiful if the gcd of all its elements is bigger than 1, i.e. . Mike wants to change his sequence in order to make it be

GCD(st表)

GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 3432    Accepted Submission(s): 1227 Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There a