나는 몇 가지 단계를 설명합니다 :
첫 번째 단계 :
을 0 to X
및 0 to Y-1
사이에 계산에 의해 X
및 Y
는 항상 간단하게 사이의 범위 문제의이 종류를 해결하기 위해, 다음을 빼기 결과. 당신이 0과 N 사이의 동일한 절반 이상 자신의 자리가 숫자를 계산 f(N)
같은 기능이있는 경우 즉, 당신의 최종 결과는 다음과 같습니다
f(X) - f(Y-1)
두 번째 단계 :
다음으로 f (N)을 계산해야합니다. 이 함수를 2 개의 하위 함수로 나눕니다. 하나는 N과 같은 자릿수의 결과를 계산하기위한 것이고 다른 하나는 N보다 작은 수의 정규화 된 수를 계산하는 것입니다 (f_less라고 부름) . 예 : N이 19354 인 경우 0에서 9999 사이의 정규화 된 숫자를 계산 한 다음 다른 방법으로 10000에서 19354 사이의 즐겨 찾기 숫자를 계산합니다. 결과가 합산 된 후입니다. 다음은이 두 가지 방법을 구현하는 방법을 설명합니다.
세 번째 단계 : 여기
, 우리는 방법을 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의 구현이다 (다시 메모이 제이션을 사용하거나 상향식 (bottom-up) 할) :
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
예 : 두 개의 1과 4 자리가 있고 2> = 4/2이므로 예 –
@ NL628 알고리즘을 자세히 설명했습니다. 어느 부분이 당신에게 명확하지 않았습니까? – Alireza