我将为您分步解释:
第一步:
要解决X和Y之间的范围问题,通常可以先从0到X和0到Y-1进行计数,然后相减得到结果。例如,如果您有一个像f(N)
这样的函数,用于计算0到N之间至少有一半数字相同的数字数量,则最终结果如下:
f(X) - f(Y-1)
第二步:
接下来我们要计算 f(N)。我们把这个函数分成两个子函数,一个用于计算与 N 有相同位数的数字的结果(我们称之为 f_equal),另一个用于计算比 N 小的数字中符合条件的数的数量(我们称之为 f_less)。例如,如果 N 是 19354,我们计算 0 到 9999 之间符合条件的数字,然后在另一个方法中计算 10000 到 19354 之间的收藏数字,之后将结果相加。接下来,我将向您介绍如何实现这两种方法。
第三步:
在这里,我们要计算 f_less 方法。您可以通过一些数学方法来完成它,但我总是更喜欢编写一个简单的 DP 来解决这些任务。我将编写递归函数,您可以使用记忆化或使用一些循环来进行自底向上的计算(这留作练习给您)。
long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
if(curDigit == maxDigit ){
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i)
if(i==favNum)
res += f_less(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar,maxDigit);
else
res += f_less(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1),maxDigit);
return res;
}
并对0到9的所有数字进行调用:
long long res = 0;
for(int maxDigit = 1; maxDigit < NUMBER_OF_DIGITS(N); ++maxDigit)
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_less(0, favNumber, 0, -1, 0, maxDigit);
第四步:
最后,我们需要计算 f_equal。在递归函数中,我们需要将数字保留为字符串,以便始终检查是否仍在小于 N 的范围内。以下是 f_equal 的实现(可以再次使用记忆化或进行自底向上的处理):
string s = NUM_TO_STRING(N);
int maxDigit = s.size();
long long f_equal(int curDigit, int favNum, int favNumCountSoFar,int nonFavNum, int nonFavNumCountSoFar, bool isEqual){
if(curDigit == maxDigit ){
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i){
if(isEqual && i>(s[curDigit]-'0')) break;
if(i==favNum)
res += f_equal(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar, isEqual && (i==(s[curDigit]-'0')));
else
res += f_equal(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1), isEqual && (i==(s[curDigit]-'0')));
}
return res;
}
并将其称为:
long long res = 0;
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_equal(0, favNumber,0, -1, 0, true);
最终结果是
res/2
。代码已经测试并且运行良好。
1231
是否符合条件?你的例子不具有代表性。 - AnT stands with Russia