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("");
  }
}

猜你喜欢

转载自www.cnblogs.com/cjc030205/p/11640827.html