私はいくつかのステップであなたを説明します:
まずステップ:常に0 to X
と0 to Y-1
の間でカウントすることで、それを簡単にX
とY
との間の範囲のこの種の問題を解決するため
をし、引きます結果。あなたは0とNの間に同じ少なくとも半分自分の数字を持っている数字を計算f(N)
のような機能を持っている場合つまりは、その後、最終的な結果は次のとおりです。
f(X) - f(Y-1)
第二ステップ:
次我々 f(N)を計算しなければならない。この関数を2つのサブ関数に分割します.1つはNと同じ桁数(f_equalと呼ぶ)の結果を計算するためのもの、もう1つはNより小さな数字を持つ修飾された数値を数える(f_lessと呼ぶ) 。例えば。 Nが19354であれば、0から9999までの適格な数を数え、次に別の方法で10000から19354の間の好きな数を数え、その結果を合計します。次に、これらの2つの方法を実装する方法について説明します。
第三ステップ:ここで
、我々はf_less方法を計算したいです。いくつかの数学によってそれを行うことができますが、私はいつもこれらの課題を解決するための簡単なDPを書くことを好みます。私はmemoizationを使うことができるかどうかにかかわらず、いくつかのループでボトムアップにすることができるかどうかにかかわらず、再帰関数を記述します(私はあなたのために練習として残します)。
long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
if(curDigit == maxDigit){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
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) //skip the leading zero
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){ //isEqual checks that whether our number is equal to N or it's lesser than it
if(curDigit == maxDigit){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
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){ //skip the leading zero
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
はいそれはあります:2つの1と4桁があり、2> = 4/2です。はい –
@ NL628アルゴリズムについて詳しく説明しました。どの部分があなたのために明確ではなかったのですか? – Alireza