POJ 3208 启示录

Posted cjc030205

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3208 启示录相关的知识,希望对你有一定的参考价值。

POJ 3208 启示录

有一个直接的想法是确定(x)个666数的位数,然后一位一位试着从高位往低位填

这样的话需要处理一个从低位往高位计666数的预处理

(f_{i,0/1/2/3})表示从低往高填到第(i)位,末尾有(0/1/2/3)个6的数的个数

再考虑预处理完了搞出位数之后怎么一步一步填

假设第(x)个666数有(tmp)位,当前从高往低填到第(i)位,枚举这位填(j),之前已经有了连续的(k)个6

有两种可能,一种是当前位可以填(j),也就是这一位填(j)时能产生的666数不少于要求的个数

如果当前位不能填(j),那么就是这一位填(j)时产生的666数不满足要求的个数,得考虑填个更大的数

考虑在之前填完的连续的(k)的个数,明显也只能在可以填的时候更新。

#include<cstdio>
#include<cstring>
#include<cmath>
const int N = 2e2+7;
#define R register
typedef long long LL;
LL f[N][5];
inline int max(int a, int b) {
  return a > b ? a : b;
}
int main() {
  f[0][0] = 1;
  for (R int i = 1; i <= 20; i++) {
    f[i][0] = 9LL * (f[i - 1][0] + f[i - 1][1] + f[i - 1][2]);
    f[i][1] = f[i - 1][0];
    f[i][2] = f[i - 1][1];
    f[i][3] = f[i - 1][2] + 10LL * f[i - 1][3];
  }
  int n, T;
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    int tmp = 3;
    while (f[tmp][3] < n) tmp++;
    for (R int i = tmp, k = 0; i > 0; i--) {
      //LL res = f[i - 1][3];
      for (R int j = 0; j <= 9; j++) {
        LL res = f[i - 1][3];
        if (j == 6 || k == 3)
          for (R int o = max(3 - (j == 6) - k, 0); o < 3; o++)
            res += f[i - 1][o];
        if (res < n)                           
          n -= res;
        else {
          if (k < 3) {
            if (j == 6) k++;
            else k = 0;
          }
          printf("%d", j);
          break;
        }
      }
    }
    puts("");
  }
}

以上是关于POJ 3208 启示录的主要内容,如果未能解决你的问题,请参考以下文章

数位DP -启示录

POJ3208:Apocalypse Someday

poj3208 Apocalypse Someday 数位dp+二分 求第K(K <= 5*107)个有连续3个6的数。

AI 时代人文写作的机遇与挑战:“诗人”微软小冰启示录

POJ2778DNA Sequence(AC自动机)

前端学习(3208):react中的事件绑定