题目
定义一种神奇的数当且仅当数位上至少有3个6,问第n个神奇的数是多少
分析
那么可以预处理出由i位数字构成的魔鬼/非魔鬼数,
f
[
i
]
[
0
]
=
9
∗
(
f
[
i
−
1
]
[
0
]
+
f
[
i
−
1
]
[
1
]
+
f
[
i
−
1
]
[
2
]
)
f[i][0]=9*(f[i-1][0]+f[i-1][1]+f[i-1][2])
f[i][0]=9∗(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][1]=f[i-1][0],f[i,2]=f[i-1][1]
f[i][1]=f[i−1][0],f[i,2]=f[i−1][1]
f
[
i
]
[
3
]
=
f
[
i
−
1
]
[
2
]
+
10
∗
f
[
i
−
1
]
[
3
]
f[i][3]=f[i-1][2]+10*f[i-1][3]
f[i][3]=f[i−1][2]+10∗f[i−1][3]
然后用试填法,求出答案
代码
#include <cstdio>
long long f[21][4];
int max(int a,int b){return a>b?a:b;}
int main(){
f[0][0]=1;
for (int i=0;i<20;i++){
for (int j=0;j<3;j++)//动态规划
f[i+1][j+1]+=f[i][j],
f[i+1][0]+=f[i][j]*9;
f[i+1][3]+=f[i][3]*10;
}
int t; scanf("%d",&t);
while (t--){
int n,m; scanf("%d",&n);
for (m=3;f[m][3]<n;m++);//找到应该的位数
for (int i=m,k=0;i;i--){
for (int j=0;j<=9;j++){
long long cnt=f[i-1][3];
if (j==6||k==3)
for (int l=max(3-k-(j==6),0);l<3;l++) cnt+=f[i-1][l];//可能性
if (cnt<n) n-=cnt;//还没有求到
else {
if (k<3) if (j==6) k++; else k=0;
putchar(j+48);//找到答案
break;
}
}
}
putchar('\n');
}
return 0;
}