由給定兩位數和給定數字之和構成的數字計數
題目描述包括計算由給定的兩位數 x 和 y 構成的 N 位數,其各位數字之和僅包含給定的數字 x 和 y。
我們需要計算可以使用數字 x 和 y(使用者輸入,大小為 N,N 的範圍為 1 到 10^6)構成的不同數字的數量。N 也將作為輸入提供。使用數字 x 和 y 構成的 N 位數必須滿足其各位數字之和只包含數字 x 和 y。
由於 N 的值可能很大,數字的計數也可能很大,因此我們需要將答案以模 1000000007(即 1e9+7)的形式返回。
下面的例子可以更好地理解這個問題。
輸入
x=4 , y=2 , N=2
輸出
1
解釋− 此處給定的輸入是 x=4,y=2,N=2,這意味著我們需要找到包含 2 位數字的數字個數。這些數字只能是 4 和 2,並且該數字的各位數字之和必須只包含給定的數字。
滿足條件的唯一可能的數字是 22。它包含 2 位數字,由給定的數字構成,並且數字的各位數字之和等於 4,即和只包含給定的數字。因此,對於此輸入,所需答案為 1。
輸入
x=1 , y=3 , N=5
輸出
15
解釋− 我們需要找到使用數字 1 和 3 構成 5 位數的個數,其各位數字之和必須只包含給定的數字。
33331, 33313, 33133, 31333, 13333, 33311, 33113, 31133, 11333, 13331, 13313, 13133, 31313, 31331, 33131.
讓我們瞭解一下演算法,以查詢使用給定數字構成的數字個數,其各位數字之和只包含給定的數字。
演算法
給定的 N 值很大,因此如果這些數字的各位數字之和只包含給定的數字,則不可能檢查每個可能的數字。因為我們只需要計算由 N 位數字 x 和 y 構成的數字個數,所以我們可以簡單地檢查數字 x 在所構成的數字中重複的次數。
假設 x 在數字中出現 i 次,那麼由於該數字僅由數字 x 和 y 構成,並且數字中的位數為 N,因此 y 將在數字中出現 (N−i) 次。因此,數字的和將為 (x*i + (N−i)*y)。
如果和只包含 x 和 y,那麼我們可以使用組合數學計算使用 i 次 x 和 (N−i) 次 y 構成的數字個數。
可以使用以下公式計算數字的個數
$\mathrm{^NC_{i}=\frac{N!}{(N−i)!*i!}或\:factorial(N)*modInverse(N−i)*modInverse(i)}$
該演算法可以分為三個部分
檢查 x 在數字中重複次數的每種可能性
我們可以簡單地在 for 迴圈中從 i=0 迭代到 i<=N,其中 N 是要考慮的數字的所需大小,以考慮 x 在數字中重複次數的每種可能性。
我們可以使用公式 (x*i + (N−i)*y) 檢查每種情況下的數字之和,其中 i 是 x 在數字中重複的次數,範圍為 [0,N]。
檢查數字之和是否只包含 x 和 y 作為其數字
由於使用數字 x 和 y 構成的數字之和可以計算如下
sum=(x*i + (N−i)*y),其中 i 是 x 在數字中出現的次數,(N−i) 表示 y 在數字中出現的次數。
我們將建立一個函式來檢查數字的和。在函式中,我們將使用 while 迴圈迭代,直到和變為 0,並使用模運算子檢查和的每一位數字。
sum mod 10 將給出數字的最後一位數字,因此我們將檢查數字的最後一位數字是否等於 x 或 y。如果它等於 x 或 y,我們將只將數字除以 10 來檢查下一位數字,直到和變為 0。如果和的每一位數字都等於 x 或 y,那麼我們將返回 true。如果數字的任何一位數字都不等於 x 或 y,我們將返回 false。
如果和只包含 x 和 y 數字,則查詢使用 i 次 x 數字構成數字的方法數
在檢查 i 的每個可能值時(其中 i 表示 x 在 N 位數字中出現的次數),如果由 i 次 x 數字和 (N−i) 次 y 數字構成的數字的各位數字之和只包含數字 x 和 y,我們將使用組合數學計算使用 i 次 x 數字和 (N−i) 次 y 數字構成 N 位不同數字的方法數。
計算在數字中排列 i 次 x 數字以構成不同數字的方法數的公式是 $\mathrm{^NC_{i}=\frac{N!}{(N-i)!*i!}}$。由於 $\mathrm{^NC_{i}=^NC_{N-i}}$,我們可以計算兩者中的任何一個。
$\mathrm{^NC_{i}=factorial}$
為了計算方法數,我們將預先計算從 0 到 N 最大值(即 10^6)的階乘和逆階乘的值,並將它們儲存在大小為 10^6+1 的陣列中。
可以使用以下公式計算 modInverse
modInverse(N!)= modInverse((N+1)!)*(N+1)。
由於我們有所有可能的階乘值,我們將使用上述公式計算方法數。階乘值可能很大,因此我們將以 1e9+7 為模儲存該值。
我們將新增可以使用特定數量的數字構成的不同數字的方法數,並將它們新增到答案中,進一步檢查每個可能的數字位數並找到數字的個數。
我們可以使用此演算法找到由給定 N 位數構成的數字個數,其各位數字之和只包含給定的數字。為了解決這個問題,我們將在我們的方法中使用該演算法。
方法
以下是按照演算法在我們的方法中實現以查詢數字個數的步驟
我們將建立一個函式來計算使用給定數字構成的數字個數,其各位數字之和只包含給定的數字。
我們將使用 for 迴圈從 i=0 迭代到 i<=N,以檢查每個具有 i 次 x 數字和 (N−i) 次 y 數字的數字。
如果具有 i 次 x 數字和 (N−i) 次 y 數字的數字的各位數字之和只包含 x 和 y 作為其數字,我們將使用公式 $\mathrm{^NC_{i}}$ 計算我們可以使用 i 次 x 數字構成 N 位不同數字的方法數。
示例
//function to count the number formed by given digits whose sum having the given digit #include <bits/stdc++.h> using namespace std; const int n=1000001; const int mod=1e9+7; //initialising array to store values of factorial and inverseFactorial till n int fac[n]={0}; int inverseFac[n]={0}; //to calculate the inverse factorial of the last index int lastFactorialIndex(int n,int m) { int p=m; int a=1,b=0; if(m==1) { return 0; } while(n>1) { int quotient=n/m; int temp=m; m=n%m; n=temp; temp=b; b=a-quotient*b; a=temp; } if(a<0) { a=a+p; } return a; } //function to store the values of factorial in the array void factorial() { fac[0]=1; fac[1]=1; for(int i=2;i<n;i++) { //since n!=n*(n-1)! fac[i]=(long long)fac[i-1]*i%mod; } } //function to calculate the inverse factorials for all values till n void inverseFactorial() { inverseFac[0]=1; inverseFac[1]=1; //calling the function to calculate the inverse factorial of last index inverseFac[n-1]=lastFactorialIndex(fac[n-1],mod); for(int i=n-2;i>=2;i--) { //inverse(i!)=inverse((i+1)!)*(i+1) inverseFac[i]=((long long)inverseFac[i+1]*(long long)(i+1)) % mod; } } //function to check if the sum has only digits x and y bool cal(int sum,int x,int y) { if(sum==0) { return false; } while(sum>0) { if((sum%10)!=x && (sum%10)!=y) //checking each digit of the number { return false; } sum=sum/10; } return true; } //function give the number of ways of distinct numbers can be formed using i times x digit long long int combinatorics(int n,int r) { //using the formula nCr= factorial(n) * modInverse(n-r)*modInverse(r) % mod long long int ways= (long long)fac[n]*(long long)inverseFac[r] %mod *(long long)inverseFac[n-r]%mod; return ways; } // function to calculate count of numbers int count_numbers(int m,int x,int y) { //if both the digits are equal if(x==y) { if(cal(m*x,x,y)==true){ return 1; } else{ return 0; } } int count=0; for(int i=0;i<=m;i++) { if(cal(i*x + (m-i)*y,x,y)) //checking for each possible case of x digit appearing i times { //if sum has the digits x and y, calculate the number of ways count = (count + combinatorics(m,i)) % mod; } } return count; } int main() { //calling the function to pregenerate factorials and inverse factorials factorial(); inverseFactorial(); int m=188; int x=8; int y=4; cout<<count_numbers(m,x,y); return 0; }
輸出
917113677
時間複雜度− O(n*logn)
空間複雜度− O(n),因為我們使用了大小為 n 的陣列來儲存階乘和逆階乘的值。
結論
本文討論了確定可以使用給定的兩位數生成的數字個數的問題,其數字的各位數字之和只包含數字 x 和 y。我們使用了組合數學原理來確定數字的總數,而不是檢查每個數字。對有效的 C++ 解決方案進行了詳細解釋。
閱讀完這篇文章後,我希望您對這個問題和解決方案有更好的理解。