Codeforces 55D

基本的数位DP,注意记录那些状态可以用最小的空间判断出整除性。

#include <cstdio>
#include <cstring>
using namespace std;

#define D(x) 

const int MAX_DIGIT_NUM = 20;

int f[MAX_DIGIT_NUM];
long long memoize[MAX_DIGIT_NUM][5][7][8][9][1 << 8];
bool contain[10];

int to_digits(long long n)
{
    int ret = 0;
    while (n > 0)
    {
        f[ret++] = n % 10;
        n /= 10;
    }
    return ret;
}

bool check(int r5, int r7, int r8, int r9, int status)
{
    D(printf("%d%d%d%d %d\n", r5, r7, r8, r9, status));
    memset(contain, 0, sizeof(contain));
    int i = 2;
    while (status)
    {
        contain[i++] = status & 1;
        status >>= 1;
    }
    if (contain[2] && r8 % 2)
    {
        return false;
    }
    if (contain[3] && r9 % 3)
    {
        return false;
    }
    if (contain[4] && r8 % 4)
    {
        return false;
    }
    if (contain[5] && r5 % 5)
    {
        return false;
    }
    if (contain[6] && (r8 % 2 || r9 % 3))
    {
        return false;
    }
    if (contain[7] && r7)
    {
        return false;
    }
    if (contain[8] && r8 % 8)
    {
        return false;
    }
    if (contain[9] && r9 % 9)
    {
        return false;
    }
    D(puts("***"));
    return true;
}

long long dfs(int digit, bool less, int r5, int r7, int r8, int r9, int status)
{
    D(printf("%d\n", status));
    if (digit < 0)
    {
        return check(r5, r7, r8, r9, status);
    }
    if (less && memoize[digit][r5][r7][r8][r9][status] != -1)
    {
        return memoize[digit][r5][r7][r8][r9][status];
    }
    int limit = less ? 9 : f[digit];
    long long ret = 0;
    for (int i = 0; i <= limit; i++)
    {
        int next_status = i < 2 ? status : status | (1 << (i - 2));
        ret += dfs(digit - 1, less || i < f[digit], i % 5, (r7 * 10 + i) % 7, (r8 * 10 + i) % 8, (r9 * 10 + i) % 9, next_status);
    }
    if (less) 
    {
        memoize[digit][r5][r7][r8][r9][status] = ret;
    }
    return ret;
}

long long work(long long n)
{
    if (n == 0)
    {
        return 1;
    }
    int len = to_digits(n);
    return dfs(len - 1, false, 0, 0, 0, 0, 0);
}

int main()
{
    int t;
    scanf("%d", &t);
    memset(memoize, -1, sizeof(memoize));
    while (t--)
    {
        long long a, b;
        scanf("%I64d%I64d", &a, &b);
        printf("%I64d\n", work(b) - work(a - 1));
    }
    return 0;
}
View Code

 

posted @ 2015-02-24 11:29  金海峰  阅读(241)  评论(0编辑  收藏  举报