zoukankan      html  css  js  c++  java
  • 广二模拟赛 Problem A: 青春野狼不做理性小魔女的梦 解题报告

    Problem A: 青春野狼不做理性小魔女的梦

    题意

    给一个长为(k)的序列(A)和一个数(n),给出一部分(A_i)的值,另一部分为(-1),代表不知道这个(A_i)是多少,求满足(sumlimits_{i=1}^kA_ix_iequiv 1pmod m)有整数解条件下的方案数,数是这么填的(1le mle n,1 le A_ile m),填(m)和不知道的(A_i)

    说明

    (10^9+7)取模

    对所有数据(1le kle 50,1le nle 10^9,-1le A_ile 10^9)


    当时就想到了[HAOI2018]奇怪的背包

    然后就知道需要(gcd(A_1,A_2,dots,m)=1),注意要把(A_i=0)的先扔出去。

    但是那个题是(dp),把约数丢进去当状态就可以了,受到思维的影响,我就没从(dp)的坑里出去...成功的忽略了这个题推式子的本质。

    (g_i)代表模数为(i)时的答案

    需要分情况讨论,如果所有的(A_i=-1)

    [egin{aligned} g_n&=sum_{i_1=1}^nsum_{i_2=1}^ncdotssum_{i_k=1}^n[gcd(i_1,i_2,dots,i_n,n)=1]\ &=sum_{d=1}^nmu(d)sum_{i_1=1}^nsum_{i_2=1}^ncdotssum_{i_k=1}^n[d|gcd(i_1,i_2,dots,i_n,n)]\ &=sum_{d|n}mu(d)(frac{n}{d})^k end{aligned} ]

    [F(n)=sum_{i=1}^n i^k ]

    那么答案为

    [egin{aligned} ans&=sum_{i=1}^nsum_{d|i}mu(d)(frac{i}{d})^k\ &=sum_{d=1}^nmu(d)sum_{d|i}(frac{i}{d})^k\ &=sum_{d=1}^nmu(d)F(lfloorfrac{n}{d} floor) end{aligned} ]

    前面的(mu)杜教筛搞一下,后面的(F)拉格朗日插值搞一下,复杂度并不会算..

    如果不是所有的(A_i=-1),设所有非(-1)(A_i)(gcd)(s),那么式子可以推出来是

    [sum_{d|s}mu(d)F(lfloorfrac{n}{d} floor) ]


    Code:

    #include <cstdio>
    #include <algorithm>
    #include <unordered_map>
    std::unordered_map <int,int> Mu;
    const int N=2e6+1;
    const int mod=1e9+7;
    const int M=55;
    int pri[N],ispri[N],mu[N],cnt;
    int k,n,A[M],fl[M],fr[M],fac[M],inv[M],py[M],s=-1;
    #define add(a,b) ((a+b)%mod)
    #define mul(a,b) (1ll*(a)*(b)%mod)
    int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
    void init()
    {
        k+=2,fac[0]=1;
        for(int i=1;i<=k;i++) py[i]=add(py[i-1],qp(i,k-2)),fac[i]=mul(fac[i-1],i);
        inv[k]=qp(fac[k],mod-2);
        for(int i=k-1;~i;i--) inv[i]=mul(inv[i+1],i+1);
        mu[1]=1;
        for(int i=2;i<N;i++)
        {
            if(!ispri[i])
            {
                pri[++cnt]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=cnt&&i*pri[j]<N;j++)
            {
                int x=i*pri[j];
                ispri[x]=1;
                if(i%pri[j])
                    mu[x]=-mu[i];
                else
                    break;
            }
        }
        for(int i=2;i<N;i++) mu[i]+=mu[i-1];
    }
    int Sum(int n)
    {
        if(n<N) return mu[n];
        if(Mu.find(n)!=Mu.end()) return Mu[n];
        int ret=1;
        for(int r,l=2;l<=n;l=r+1)
        {
            r=n/(n/l);
            ret-=(r+1-l)*Sum(n/l);
        }
        return Mu[n]=ret;
    }
    int getF(int n)//sum_{i=1}^n i^k
    {
        if(n<=k) return py[n];
        fl[0]=fr[k+1]=1;
        for(int i=1;i<=k;i++) fl[i]=mul(fl[i-1],n-i);
        for(int i=k;i;i--) fr[i]=mul(fr[i+1],n-i);
        int ret=0;
        for(int i=1;i<=k;i++)
            ret=add(ret,mul(k-i&1?-1:1,mul(py[i],mul(mul(fl[i-1],fr[i+1]),mul(inv[i-1],inv[k-i])))));
        return ret;
    }
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    void work1()
    {
        int ans=0;
        for(int l=1,r;l<=n;l=r+1)
        {
            r=n/(n/l);
            ans=add(ans,mul(add(Sum(r),mod-Sum(l-1)),getF(n/l)));
        }
        ans=add(ans,mod);
        printf("%d
    ",ans);
    }
    int getmu(int n)
    {
        int ret=1;
        for(int i=1;pri[i]*pri[i]<=n;i++)
            if(n%pri[i]==0)
            {
                ret=-ret;
                n/=pri[i];
                while(n%pri[i]==0) n/=pri[i],ret=0;
            }
        if(n!=1) ret=-ret;
        return ret;
    }
    void work2()
    {
        int ans=0,i=1;
        for(i=1;i*i<s;i++)
        {
            if(s%i) continue;
            int t=s/i;
            ans=add(ans,mul(getmu(i),getF(n/i)));
            ans=add(ans,mul(getmu(t),getF(n/t)));
        }
        if(i*i==s)
            ans=add(ans,mul(getmu(i),getF(n/i)));
        ans=add(ans,mod);
        printf("%d
    ",ans);
    }
    int main()
    {
        int k_;scanf("%d%d",&k_,&n);
        for(int a,i=1;i<=k_;i++)
        {
            scanf("%d",&a);
            if(a) A[++k]=a;
        }
        std::sort(A+1,A+1+k);
        if(!k||A[k]==-1) return init(),work1(),0;//全是-1
        while(k&&~A[k]) if(~s) s=gcd(s,A[k]?A[k]:s),--k;else s=A[k--];
        init();
        work2();
        return 0;
    }
    

    2018.12.26

  • 相关阅读:
    Laravel 通知
    LARAVEL 6 + VUE + SEMANTIC UI
    Laravel 从入门到精通教程【预备篇、基础篇】
    Laravel Vue.js 聊天室
    GIT代码管理: git remote add 【转载】
    Laravel Vuejs 实战:开发知乎 (45-47)用户设置
    Laravel Vuejs 实战:开发知乎 (42-44)用户头像
    如何在运行时更改JMeter的负载
    Jmeter Grafana Influxdb 环境搭建
    实时结果
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10178609.html
Copyright © 2011-2022 走看看