由给定两位数和给定数字之和构成的数字计数
题目描述包括计算由给定的两位数 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 构成的数字个数。
可以使用以下公式计算数字的个数
NCi=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 数字以构成不同数字的方法数的公式是 NCi=N!(N−i)!∗i!。由于 NCi=NCN−i,我们可以计算两者中的任何一个。
NCi=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 作为其数字,我们将使用公式 NCi 计算我们可以使用 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++ 解决方案进行了详细解释。
阅读完这篇文章后,我希望您对这个问题和解决方案有更好的理解。