广二模拟赛 Problem A: 青春野狼不做理性小魔女的梦 解题报告

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

题意

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

说明

\(10^9+7\)取模

对所有数据\(1\le k\le 50,1\le n\le 10^9,-1\le A_i\le 10^9\)


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

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

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

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

需要分情况讨论,如果所有的\(A_i=-1\)
\[ \begin{aligned} g_n&=\sum_{i_1=1}^n\sum_{i_2=1}^n\cdots\sum_{i_k=1}^n[\gcd(i_1,i_2,\dots,i_n,n)=1]\\ &=\sum_{d=1}^n\mu(d)\sum_{i_1=1}^n\sum_{i_2=1}^n\cdots\sum_{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 \]
那么答案为
\[ \begin{aligned} ans&=\sum_{i=1}^n\sum_{d|i}\mu(d)(\frac{i}{d})^k\\ &=\sum_{d=1}^n\mu(d)\sum_{d|i}(\frac{i}{d})^k\\ &=\sum_{d=1}^n\mu(d)F(\lfloor\frac{n}{d}\rfloor) \end{aligned} \]
前面的\(\mu\)杜教筛搞一下,后面的\(F\)拉格朗日插值搞一下,复杂度并不会算..

如果不是所有的\(A_i=-1\),设所有非\(-1\)\(A_i\)\(\gcd\)\(s\),那么式子可以推出来是
\[ \sum_{d|s}\mu(d)F(\lfloor\frac{n}{d}\rfloor) \]


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\n",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\n",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

转载于:https://www.cnblogs.com/butterflydew/p/10178609.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值