DP - 數位DP - 度的數量

DP - 數位DP - 度的數量

求給定區間 [X,Y] 中滿足下列條件的整數個數:這個數恰好等於 K 個互不相等的 B 的整數次冪之和。

例如,設 X=15,Y=20,K=2,B=2,則有且僅有下列三個數滿足題意:

17=24+20
18=24+21
20=24+22
輸入格式
第一行包含兩個整數 X 和 Y,接下來兩行包含整數 K 和 B。

輸出格式
只包含一個整數,表示滿足條件的數的個數。

數據範圍
1≤X≤Y≤231−1,
1≤K≤20,
2≤B≤10

輸入樣例:
15 20
2
2
輸出樣例:
3

分析:

1藉助前綴和的思想,先求1~N滿Sn[l,r]=SrSl1N中滿足條件的數的個數S_n,再求區間[l,r]中的個數=S_r-S_{l-1}。

Count1Count函數求1~N滿NBN中滿足條件的數的個數,將N先轉化爲一個B進制數存入數組。

KBiBK10依據題意,要恰好表示成K個B^i次方的數之和,等價於B進製表示下有K位爲1,其餘爲0。

NBK1問題轉化在N的B進製表示下,選擇K個位置取1的所有取法的方案總數。

從高位到低位依次遍歷,
NBV=an1an2...a0last1設N的B進製表示爲V=a_{n-1}a_{n-2}...a_{0},當前已經選取了last個'1':

ai>0:i0ai1...a0VCiKlastiKlast1①、若a_i>0:\\\qquadⅠ、我們可以將第i位取0,這樣a_{i-1}...a_0無論取何值均不會大於V。總方案數爲C_i^{K-last},\\\qquad即在剩下i位中選擇K-last個位置取'1'。

i1ai>1ai1...a0VCiKlast1iKlast11退\qquad Ⅱ、我們可以將第i位取1,\\\qquad若a_i>1,a_{i-1}...a_0無論取何值均不會大於V。總方案數爲C_i^{K-last-1},\\\qquad即在剩下i位中選擇K-last-1個位置取'1'。此時,所有合法方案已均被計算出來,退出循環。

ai=1last++\qquad 若a_i=1,後面的取法將在第Ⅰ步被計算出來,因此這裏不必重複計算,last++後直接看下一位。

ai=0:②、若a_i=0:後面的合法方案同樣會在①-Ⅰ中被計算出來,直接看下一位。

a0K1Vai1V③、最後,若考慮到a_0時已經取了K個1,說明V的第a_i位都恰好是1,答案還要再加上等於V的方案。

代碼:

#include<iostream>
#include<vector>

using namespace std;

const int N=35;

int K,B;
int C[N][N];

void cal()
{
    for(int i=0;i<N;i++)
        for(int j=0;j<=i;j++)
            if(!j) C[i][j]=1;
            else C[i][j]=C[i-1][j]+C[i-1][j-1];
}

int dp(int n)
{
    if(!n) return 0;
    vector<int> V;
    while(n) V.push_back(n%B),n/=B;
    
    int res=0,last=0;
    for(int i=V.size()-1;i>=0;i--)
    {
        int x=V[i];
        if(x)
        {
            res+=C[i][K-last];
            if(x>1)
            {
                if(K-last-1>=0) res+=C[i][K-last-1];
                break;
            }
            else
            {
                last++;
                if(last>K) break;
            }
        }
        if(i==0 && last==K) res++;
    }
    
    return res;
}

int main()
{
    cal();
    
    int l,r;
    cin>>l>>r>>K>>B;
    
    cout<<dp(r)-dp(l-1)<<endl;
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章