Educational Codeforces Round 33 (Rated for Div. 2) E. Counting Arrays【组合数学】

题目链接:https://codeforc.es/problemset/problem/893/E
题目大意:有qq次询问,每次给定x,,yx,,y,问满足序列FF长度为yy,且i=1yFi=x\sum_{i=1}^yF_i=x的序列数目,序列可为负。
思路:要计算满足条件的序列数目,首先想到的是将xx素因数分解,然后对于每次素因子pip_i,统计其出现的次数cntcnt,要怎么把这cntcnt个数分成yy份呢,我们就想到了隔板法,类似于将nn个小球放进mm个盒子中,可以放空。

那么对于cntcnt来说,组合的种类数就是Ccnt+y1y1C_{cnt+y-1}^{y-1}

然后题目要求可以为负数,但是x>0x>0,所以负数只能出现偶数次,即对于yy个数来说,负数的种类数就是Cy0+Cy2+Cy4+Cy2y2=2y1C_{y}^0+C_{y}^2+C_{y}^4\dots+C_{y}^{2*\lfloor\frac{y}{2}\rfloor}=2^{y-1}
AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e7+10;
    const int mod=1e9+7;
    typedef long long ll;
    ll qpow(ll x,ll y){
        ll ans=1;
        while(y>0){
            if(y&1){
                ans=ans*x%mod;
            }
            y>>=1;
            x=x*x%mod;
        }
        return ans;
    }
    ll f[maxn];
    ll inv[maxn];
    void calf()
    {
        f[0]=1;
        for(int i=1;i<maxn;i++){
            f[i]=(f[i-1]*i)%mod;
        }
        inv[maxn-1]=qpow(f[maxn-1],mod-2);
        for(int i=maxn-2;~i;i--){
            inv[i]=inv[i+1]*(i+1)%mod;
        }
    }
    ll C(int n,int m){
        if(n<m||m<0){
            return 0;
        }
        return f[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int main()
    {
        int q;
        int x,y;
        int cnt;  
        calf();  
        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&x,&y);
            ll ans=1;
            for(int i=2;i*i<=x;i++){
                cnt=0;
                if(x%i==0){
                    while(x%i==0){
                        x/=i;
                        cnt++;
                    }
                    ans=ans*C(cnt+y-1,y-1)%mod;
                }
            }
            if(x>1){
                ans=ans*y%mod;
            }
            ans=ans*qpow(2,y-1)%mod;
            printf("%lld\n",ans);
        }
        return 0;
    }

隔板法参考:https://blog.csdn.net/qq_39942341/article/details/80246780

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章