HDU 4675 - GCD of Sequence

解题思路参考: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("\n");
70     }
71 }

 



 

posted @ 2017-04-17 22:16  Dilthey  阅读(241)  评论(0)    收藏  举报