POJ 3689 Apocalypse Someday [数位DP]
Time Limit: 1000MS | Memory Limit: 131072K | |
Total Submissions: 1807 | Accepted: 873 |
Description
The number 666 is considered to be the occult “number of the beast” and is a well used number in all major apocalypse themed blockbuster movies. However the number 666 can’t always be used in the script so numbers such as 1666 are used instead. Let us call the numbers containing at least three contiguous sixes beastly numbers. The first few beastly numbers are 666, 1666, 2666, 3666, 4666, 5666…
Given a 1-based index n, your program should return the nth beastly number.
Input
The first line contains the number of test cases T (T ≤ 1,000).
Each of the following T lines contains an integer n (1 ≤ n ≤ 50,000,000) as a test case.
Output
For each test case, your program should output the nth beastly number.
Sample Input
3 2 3 187
Sample Output
1666 2666 66666
Source
题意:给定一个数字串A,不含前导0,长为m。m<=9求第P小的包含666的数字 P<=109
课件上是个加强版:
给定一个数字串A,不含前导0,长为m。m<=9
求第P小的包含子串A的数字
P<=109做法:
二分答案X,转为判断小于等于X的包含子串A的数字有多少个
F[i][j][k][l]表示,填完前i位,KMP指针指向A的第j位,之前是否出现过子串A的状态为k(0/1),下一位能否任意填数的状态为l(0/1),的方案数
这里也可以用类似的做法二分答案
或者可以不二分答案,因为答案是多少位可以判断出来,直接数位DP行了
d[i][0]表示i位数中首位不为6且不含666的数的数量
d[i][1]表示i位数中首位连续1个6并且不含666的数的数量
d[i][2]表示i位数中首位连续2个6并且不含666的数的数量
d[i][3]表示i位数中含有666的数的数量
然后依次从小到大判断每一位填什么行了,记录sum为当前含666的数字的个数,six为当前需要几个6
特判真的好麻烦,于是借鉴 http://blog.csdn.net/keshuai19940722/article/details/41087343 使用g[i][j]表示当前需要i个6,填了数字j后还需要几个6
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=12; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int g[4][12] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {3, 3, 3, 3, 3, 3, 0, 3, 3, 3}, {3, 3, 3, 3, 3, 3, 1, 3, 3, 3}, {3, 3, 3, 3, 3, 3, 2, 3, 3, 3} }; int d[N][4]; void dp(){ d[0][0]=1; for(int i=1;i<=10;i++){ d[i][0]=(d[i-1][0]+d[i-1][1]+d[i-1][2])*9; d[i][1]=d[i-1][0]; d[i][2]=d[i-1][1]; d[i][3]=d[i-1][3]*10+d[i-1][2]; //printf("d %d %d\n",i,d[i][3]); } } int n; int main(){ //freopen("in.txt","r",stdin); dp(); int T=read(); while(T--){ n=read(); int dit=0,six=3,sum=0; while(d[dit][3]<n) dit++; //printf("dit %d\n",dit); while(dit){//printf("hidit %d %d\n",dit,sum); for(int i=0;i<=9;i++){ int _=0; for(int j=3;j>=g[six][i];j--) _+=d[dit-1][j]; //printf("_ %d %d %d\n",_,sum,six); if(sum+_>=n){ printf("%d",i); six=g[six][i]; break; } sum+=_; } dit--; } putchar('\n'); } }