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

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