SRM526 Div2 Hard(1000) SumOfLuckiness

SumOfLuckiness

lucky(x)を0からxまでのluckinessの合計とすると、答えはlucky(B)-lucky(A-1)。まずは、iとjそれぞれについて、i桁以下で(4の個数)-(7の個数)=jとなる整数の個数T[i][j]を動的計画法で求める。例えば、x=526とすると、0-99, 100-199, 200-299, 300-399, 400-499, 500-509, 510-119, 520, 521, 522, 523, 524, 525, 526と分けることで、Tを使ってそれぞれの組のluckinessの合計が求められる。

#include <vector>
#include <map>
using namespace std;

long long lucky( int A )
{
    //  T[i][j]: i桁以下で(4の個数)-(7の個数)=jな整数の個数
    map<int,int> T[10];
    T[0][0] = 1;

    for ( int i=0; i<10-1; i++ )
        for ( int j=-i; j<=i; j++ )
            for ( int k=-1; k<=1; k++ )
                T[i+1][j+k] += (k==0?8:1)*T[i][j];

    int t = 1000000000;
    int f = 0;
    long long ans = 0;
    for ( int i=9; i>=0; i-- )
    {
        for ( int j=0; j<A/t; j++ )
        {
            int d = j==4 ? 1 : j==7 ? -1: 0;
            for ( int k=-i; k<=i; k++ )
                ans += T[i][k]*abs(f+d+k);
        }
        f += A/t==4 ? 1 : A/t==7 ? -1 : 0;
        A -= A/t*t;
        t /= 10;
    }
    ans += abs(f);

    return ans; 
}

class SumOfLuckiness{public:
long long theSum( int A, int B )
{
    return lucky(B)-lucky(A-1);
}};