• HDU4675_GCD of Sequence


    很有意思的一个数论题。

    是这样的,给你一个数数组a[i],其中给出的每一个数字和要求的数字方位都是[1,m],现在问你根据a[]构造一个b[],且a和b中间的不相等的元素的个数恰好有k个。

    现在问你gcd(b[])分别为1,2,……,m的个数分别有多少种可能情况。

    额。。。是这样来考虑的。——————容斥原理。

    有点像素数筛选,但是复杂一点。

    对于个数我们需要从大到小来求解(这里的缘由自己想象就知道了)

    假设当前我需要求解有多少个情况满足gcd(b[])=x,那么显然b中的所有的数都必须是x的倍数。

    首先我们可以直接统计出来在a中有多少个数不是x的倍数,那么显然这些数是一定要被更改掉的。

    如果非x倍数个数大于k个,那么说明当前的个数就是0了。

    接下来搞定了不相等的,我们还可能有一种情况就是改变的个数还不够,所以在那些已经是倍数的位置我们还需要进行更改。

    这里直接选出组合数,然后依次求出有多少种情况就可以了。

    最后把多余的情况减去就得到答案了。

    注意不要写挫了,因为很可能由于常数的问题就会T。T_T

     

     

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define maxn 300003
    #define M 1000000007
    typedef long long ll;
    using namespace std;
    
    int a[maxn],f[maxn],n,m,k,ai,tep;
    ll P[maxn],Q[maxn];
    
    ll power(ll x,ll y)
    {
        if (x==0) return 0;
        if (x==1 || y==0) return 1;
        ll tot=1;
        while (y)
        {
            if (y&1) tot=(tot*x)%M;
            y>>=1;
            x=(x*x)%M;
        }
        return tot;
    }
    
    ll C(ll x,ll y)
    {
        if (y==0 || x==y) return 1;
        ll tot=(P[x]*Q[y])%M;
        tot=(tot*Q[x-y])%M;
        return tot;
    }
    
    int main()
    {
        ll cur,tot,num;
        Q[1]=P[0]=1;
        for (int i=1; i<maxn; i++) P[i]=(P[i-1]*i)%M,Q[i]=power(P[i],M-2);
        while (scanf("%d%d%d",&n,&m,&k)!=EOF)
        {
            for (int i=1; i<=m; i++) a[i]=f[i]=0;
            for (int i=1; i<=n; i++)
            {
                scanf("%d",&ai);
                a[ai]++;
            }
            for (int i=m; i>0; i--)
            {
                cur=0; tot=1; num=m/i;
                for (int j=i; j<=m; j+=i) cur+=a[j];
                if (n-cur>k)
                {
                    f[i]=0;
                    continue;
                }
                tot=power(num,n-cur); 
                if (n-cur!=k)
                {
                    tep=(C(cur,k+cur-n)*power(num-1,k+cur-n))%M;
                    tot=(tot*tep)%M;
                }
                f[i]=tot;
                for (int j=i+i; j<=m; j+=i)
                {
                    f[i]-=f[j];
                    if (f[i]<0) f[i]+=M;
                }
            }
            printf("%d",f[1]);
            for (int i=2; i<=m; i++) printf(" %d",f[i]);
            printf("
    ");
        }
        return 0;
    }

     

    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    最全面的iOS和Mac开源项目和第三方库汇总
    15 个 Android 通用流行框架大全
    Android中常用的优秀开源框架
    iOS中拉伸图片的几种方式
    iOS View自定义窍门——UIButton实现上显示图片,下显示文字
    Java Queue的使用
    java用volatile或AtomicBoolean实现高效并发处理 (只初始化一次的功能要求)
    android开发音乐播放器--Genres和Art album的获取
    一个神奇的控件——Android CoordinatorLayout与Behavior使用指南
    在CodeBlocks 开发环境中配置使用OpenCV (ubuntu系统)
  • 原文地址:https://www.cnblogs.com/lochan/p/3446860.html
Copyright © 2020-2023  润新知