HDU 4675

来源:互联网 发布:mysql 断电 无法启动 编辑:程序博客网 时间:2024/06/06 00:14

解题思路参考: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


#include<cstdio>#include<cstring>#define MOD 1000000007#define MAX 300005using namespace std;typedef long long ll;ll C[MAX],ans[MAX];int a[MAX],b[MAX],num[MAX];ll pow(ll a,ll b){ll r=1,base=a%MOD;while(b){if(b&1) r*=base , r%=MOD;base*=base;base%=MOD;b>>=1;}return r;}ll inv(ll a,ll p){return pow(a, p-2);}//费马求a关于b的逆元int main(){int n,m,k;    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        memset(num,0,sizeof(num));        C[n-k]=1;//当cnt=n-k时,C[cnt][n-k]=C[n-k][n-k]=1         for(int i = n-k+1;i <= n;i++)//当cnt = n-k+1 to n 时,计算C[cnt][n-k]        {            C[i] = C[i-1]*i%MOD*inv(i-(n-k),MOD)%MOD;        }        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            num[a[i]]++;        }        for(int d=m;d>=1;d--)        {            int cnt=0;            ll accu=0;            for(int times=1;times * d <= m;times++)            {                cnt+=num[times * d];                if(times > 1) accu = (accu + ans[times *d])%MOD;            }            int l=m/d;            if(l==1)            {                if(k - (n - cnt) == 0) ans[d]=1;//如果正好有k个不是d的倍数                 else ans[d]=0;//如果k>(n-cnt),那么剩下的就要在cnt里面找数进行修改,但是这时l==1,因此修改不了;或者k<(n-cnt),这时修改了n-cnt个数,已经超过了k个,不满足             }            else            {                if(k < n - cnt) ans[d]=0;                else                {                    ll ans_tmp=1;                    ans_tmp=ans_tmp*C[cnt]%MOD;                    ans_tmp=ans_tmp*pow(l-1,k-n+cnt)%MOD;                    ans_tmp=ans_tmp*pow(l,n-cnt)%MOD;                    ans[d]=(ans_tmp-accu+MOD)%MOD;                }            }        }        for(int d=1;d<=m;d++)        {            if(d>1) printf(" ");            printf("%I64d",ans[d]);        }        printf("\n");    }}



0 0