HDU3555 폭탄 문제는 비트 DP를 중지

링크 제목 : http://acm.hdu.edu.cn/showproblem.php?pid=3555
타이틀 효과 : 찾는 \ ([1, N] \ ) 의 범위에서 약간의 "49"을 다수 포함
아이디어를 문제가 해결 :
이것은 우리가 고려하는 두 가지 솔루션으로 나눌 수 있습니다 무언가이다 : 첫 번째하여 감소 후 숫자 "49"의 수를 포함하지 않는 찾고, 다른 하나는 직접 요청이 숫자 "49"의 수를 포함입니다.

해결 방법 1 : 숫자는 숫자 "49"를 포함하지 않는 것을 발견

이러한 방법으로 우리는 먼저 비트 DP 수가 결정 \ ([0, N-] \) 의 간격은 다수의 "49"(값은로 가정 적은 수의 범위를 포함하지 않는다 (X \) \ ), 그 응답이 (n \ + -THE X-1 \) .

우리는 기능을 디자인 할 수 dfs(int pos, int stat, bool limit)복귀 간격 것을 \ ([0, N] \ ) 약간의 범위의 숫자를 포함하지 않는, "49"에있어서,

  • pos 이 숫자가 현재 위치이고;
  • stat 프리가 숫자 '4'아니다 나타낸다 (전자는 '4'가 만들어 현재 위치 '9'인 경우 "49");
  • limit 라벨의 경우 현재 (:; : 무제한 거짓 제한된 사실)을 제한.

다음 코드는 다음과 같습니다

#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
    memset(f, -1, sizeof(f));
}
long long dfs(int pos, int stat, bool limit) {
    if (pos < 0) return 1;
    if (!limit && f[pos][stat] != -1) return f[pos][stat];
    int up = limit ? a[pos] : 9;
    long long tmp = 0;
    for (int i = 0; i <= up; i ++) {
        if (stat && i == 9) continue;
        tmp += dfs(pos-1, i==4, limit && i == up);
    }
    if (!limit) f[pos][stat] = tmp;
    return tmp;
}
long long get_num(long long x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, true);
}
int main() {
    init();
    scanf("%d", &T);
    while (T --) {
        scanf("%lld", &n);
        printf("%lld\n", n+1-get_num(n));
    }
    return 0;
}

해결 방법 2 :주십시오 얼마나 많은 숫자 "49"

해결 방법 1 그것을 해결하기 위해 상대적으로 간접적 인 방법입니다. 우리는한다 이런 식으로 지금 바로 해결 ([0, N] \ \ ) 많은 숫자 "49"를 포함하는 방법의 범위 내에서

우리는 기능을 디자인 할 수 dfs(int pos, int stat, bool limit)복귀 간격 것을 \ ([0, N] \ ) 약간의 범위의 숫자를 포함하지 않는, "49"에있어서,

  • pos 이 숫자가 현재 위치이고;
  • stat 프리가 숫자 '4'아니다 나타낸다 (전자는 '4'가 만들어 현재 위치 '9'인 경우 "49");
  • limit 라벨의 경우 현재 (:; : 무제한 거짓 제한된 사실)을 제한.

그것은 동일하지만, 통계 처리 할 때 같은 방법은 아니지만.

그것은 상이한 프로세싱 조건 하에서 비 제한적인 특별한 제한에 주목해야한다.

우리가 찾고한다고 가정하면 간격 \ ([0, N] \ ) "49"이송되는 몇 복수 포함하는 범위의 pos비트 및 pos+1비트는 '4'이다 pos비트들이 '9'이다, 우리는 그것을 볼 수있다 :

  1. 현재 상태가 한계 인 경우가 \ (n \ % 10 ^ { POS + 1} \) 수의 조건을 만족;
  2. 현재 상태가있는 경우, 다음의 특징을 가진 비 한정 \ (10 ^ {POS} \ ) 번호는 조건을 만족.

다음 코드는 다음과 같습니다

#include <bits/stdc++.h>
using namespace std;
long long f[66][2], n;
int T, a[66];
void init() {
    memset(f, -1, sizeof(f));
}
long long pow10(int a) {
    if (a == 0) return 1;
    if (a == 1) return 10;
    long long t = pow10(a/2);
    return t * t * (a%2 ? 10 : 1);
}
long long dfs(int pos, int stat, bool limit) {
    if (pos < 0) return 0;  // 返回0说明没找到包含49的
    if (!limit && f[pos][stat] != -1) return f[pos][stat];
    int up = limit ? a[pos] : 9;
    long long tmp = 0;
    for (int i = 0; i <= up; i ++) {
        if (stat && i == 9) {   // 说明接下来pos位的10的pos次方个数都满足条件
            // tmp += pow10(pos);   // 直接这么写是错的,此时也要考虑边界条件限制
            // 修正如下
            if (limit) tmp += n % pow10(pos) + 1;
            else tmp += pow10(pos);
        }
        else tmp += dfs(pos-1, i==4, limit && i == up);
    }
    if (!limit) f[pos][stat] = tmp;
    return tmp;
}
long long get_num(long long x) {
    int pos = 0;
    while (x) {
        a[pos++] = x % 10;
        x /= 10;
    }
    return dfs(pos-1, 0, true);
}
int main() {
    init();
    scanf("%d", &T);
    while (T --) {
        scanf("%lld", &n);
        printf("%lld\n", get_num(n));
    }
    return 0;
}

추천

출처www.cnblogs.com/quanjun/p/11964644.html