解题思路参考:http://www.cnblogs.com/kuangbin/archive/2013/08/13/3255943.html
如果gcd(b[1...n])=d,那么b[1...n]中每个b[i]都应是d的倍数,
而b[1...n]是从a[1...n]修改k个数进而变过来的,
那么,假设a[1...n]中有cnt个a[i]本来就是d的倍数,
那么首先 ( n-cnt )个不是d的倍数的必须修改,
然后,剩下的 cnt 个本来就是d的倍数的a[i]中,我们再挑选 k - ( n - cnt ) 个修改(k个要修改的数,已经修改了 n-cnt 个),就可以满足条件,
而在小于m的情况下,d的倍数有 l = floor(m/d) 个,
所以
又
所以
接下来是关于逆元的知识:http://www.cnblogs.com/linyujun/p/5194184.html
1 #include<cstdio> 2 #include<cstring> 3 #define MOD 1000000007 4 #define MAX 300005 5 using namespace std; 6 typedef long long ll; 7 ll C[MAX],ans[MAX]; 8 int a[MAX],b[MAX],num[MAX]; 9 ll pow(ll a,ll b){ 10 ll r=1,base=a%MOD; 11 while(b){ 12 if(b&1) r*=base , r%=MOD; 13 base*=base; 14 base%=MOD; 15 b>>=1; 16 } 17 return r; 18 } 19 ll inv(ll a,ll p){return pow(a, p-2);}//费马求a关于b的逆元 20 int main() 21 { 22 int n,m,k; 23 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 24 { 25 memset(num,0,sizeof(num)); 26 C[n-k]=1;//当cnt=n-k时,C[cnt][n-k]=C[n-k][n-k]=1 27 for(int i = n-k+1;i <= n;i++)//当cnt = n-k+1 to n 时,计算C[cnt][n-k] 28 { 29 C[i] = C[i-1]*i%MOD*inv(i-(n-k),MOD)%MOD; 30 } 31 for(int i=1;i<=n;i++) 32 { 33 scanf("%d",&a[i]); 34 num[a[i]]++; 35 } 36 for(int d=m;d>=1;d--) 37 { 38 int cnt=0; 39 ll accu=0; 40 for(int times=1;times * d <= m;times++) 41 { 42 cnt+=num[times * d]; 43 if(times > 1) accu = (accu + ans[times *d])%MOD; 44 } 45 int l=m/d; 46 if(l==1) 47 { 48 if(k - (n - cnt) == 0) ans[d]=1;//如果正好有k个不是d的倍数 49 else ans[d]=0;//如果k>(n-cnt),那么剩下的就要在cnt里面找数进行修改,但是这时l==1,因此修改不了;或者k<(n-cnt),这时修改了n-cnt个数,已经超过了k个,不满足 50 } 51 else 52 { 53 if(k < n - cnt) ans[d]=0; 54 else 55 { 56 ll ans_tmp=1; 57 ans_tmp=ans_tmp*C[cnt]%MOD; 58 ans_tmp=ans_tmp*pow(l-1,k-n+cnt)%MOD; 59 ans_tmp=ans_tmp*pow(l,n-cnt)%MOD; 60 ans[d]=(ans_tmp-accu+MOD)%MOD; 61 } 62 } 63 } 64 for(int d=1;d<=m;d++) 65 { 66 if(d>1) printf(" "); 67 printf("%I64d",ans[d]); 68 } 69 printf(" "); 70 } 71 }