正题
题目链接:http://poj.org/problem?id=3208
题目大意
求第X个有3个连续的6的数。
解题思路
用
fi,j(j<3)
f
i
,
j
(
j
<
3
)
表示i位,已经有j个6的方案总数。然后
fi,3
f
i
,
3
表示i位的魔鬼数的总数。
然后动态转移方程。
fi,0=9∗(fi−1,0+fi−1,1+fi−1,2)
f
i
,
0
=
9
∗
(
f
i
−
1
,
0
+
f
i
−
1
,
1
+
f
i
−
1
,
2
)
只要一个不是6的数就能间断他们
fi,1=fi−1,0
f
i
,
1
=
f
i
−
1
,
0
fi,2=fi−1,1
f
i
,
2
=
f
i
−
1
,
1
加一个6
fi,3=fi−1,2+10∗fi−1,3
f
i
,
3
=
f
i
−
1
,
2
+
10
∗
f
i
−
1
,
3
上一位加任意一个数或两个六的情况下加一个6。
然后试填就好了
code
#include<cstdio>
#include<algorithm>
using namespace std;
long long f[21][4];
int t,n,m;
int main()
{
f[0][0]=1;
for(int i=1;i<=20;i++)
{
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][3]=f[i-1][2]+10*f[i-1][3];
}//dp
scanf("%d",&t);
for(int ti=1;ti<=t;ti++)
{
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++)//填入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)//位数不足3时特判特殊判断
{
k+=(j==6);
k*=(j==6);
}
printf("%d",j);//输出
break;//填完了
}
}
}
printf("\n");
}
}