POJ3208:Apocalypse Someday

传送门

很神奇的一道题,正解是AC自动机+数位DP,个人感觉POPOQQQ大爷的方法更方便理解。

按照一般套路,先搞个DP预处理,设$f[i][0/1/2/3]$分别表示对于$i$位数,其中有多少个前0/1/2位为6的个数和整体中包含666的个数。那么就很容易得到以下转移方程。

$f[i][3]=f[i-1][3] \times 10+f[i-1][2]$

$f[i][2]=f[i-1][1]$

$f[i][1]=f[i-1][0]$

$f[i][0]=(f[i-1][0]+f[i-1][1]+f[i-1][2]) \times 9$

剩下的就比较麻烦了。

刚开始我想的是不断剔除排名从而确定每一位上的数。但是这个是很麻烦的,而且不好处理。更换一种方案就是通过二分确定这个排名的个数,只要我们能验证小于$N$的数中有多少个满足要求的数。

这个求的过程相当玄学...我也说不上来QAQ

 1 //NOIp DP apo
 2 //by Cydiater
 3 //2016.10.4
 4 #include <iostream>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <cstring>
 8 #include <string>
 9 #include <algorithm>
10 #include <queue>
11 #include <map>
12 #include <ctime>
13 #include <iomanip>
14 #include <cmath>
15 using namespace std;
16 #define ll long long
17 #define up(i,j,n)        for(ll i=j;i<=n;i++)
18 #define down(i,j,n)        for(ll i=j;i>=n;i--)
19 #define FILE "apo"
20 const ll MAXN=1e6+5;
21 const ll oo=0x3f3f3f3f;
22 const ll mod=(1<<31)-1;
23 inline ll read(){
24     char ch=getchar();ll x=0,f=1;
25     while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
26     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
27     return x*f;
28 }
29 ll f[25][10],leftt,rightt,mid,T;
30 namespace solution{
31     void pret(){
32         memset(f,0,sizeof(f));
33         f[0][0]=1;
34         up(i,1,21){
35             f[i][3]=f[i-1][3]*10+f[i-1][2];
36             f[i][2]=f[i-1][1];
37             f[i][1]=f[i-1][0];
38             f[i][0]=(f[i-1][0]+f[i-1][1]+f[i-1][2])*9;
39         }
40     }
41     ll check(ll num){
42         ll di=0,far=1,tmp=0,cnt=0,ans=0;
43         for(;far<num;far*=10,di++);
44         while(tmp<num){
45             ll re_cnt;
46             while(tmp+far<=num){
47                 tmp+=far;
48                 if(cnt==3)                    re_cnt=3;
49                 else if((tmp/far)%10==7)    re_cnt=cnt+1;
50                 else                        re_cnt=0;
51                 down(i,3,3-re_cnt)ans+=f[di][i];
52             }
53             if(cnt!=3)cnt=((tmp/far)%10==6?cnt+1:0);
54             di--;far/=10;
55         }
56         return ans;
57     }
58     ll slove(ll N){
59         leftt=1;rightt=100000000000000000LL;
60         N--;
61         while(leftt+1<rightt){
62             mid=(leftt+rightt)>>1;
63             ll tmp=check(mid);
64             if(tmp>N)    rightt=mid;
65             else        leftt=mid;
66         }
67         if(check(leftt)==N)    return leftt;
68         return    rightt;
69     }
70 }
71 int main(){
72     freopen(FILE".in","r",stdin);
73     //freopen(FILE".out","w",stdout);
74     using namespace solution;
75     pret();
76     T=read();
77     while(T--)cout<<slove(read())<<endl;
78     return 0;
79 }

时间: 2024-10-15 03:07:09

POJ3208:Apocalypse Someday的相关文章

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

/** 题目:poj3208 Apocalypse Someday 链接:http://poj.org/problem?id=3208 题意:求第K(K <= 5*107)个有连续3个6的数. 思路:数位dp+二分. dp[i][j]表示长度为i,前缀状态为j时含有的个数. j=0表示含有前导0: j=1表示前缀连续1个6 j=2表示前缀连续2个6 j=3表示前缀连续3个6 j=4表示前缀不是6: */ //#include<bits/stdc++.h> #include<cstr

POJ 3689 Apocalypse Someday [数位DP]

Apocalypse Someday 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

poj 3208 Apocalypse Someday (数位dp)

Apocalypse Someday Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 1490   Accepted: 686 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 blockb

POJ 3208 Apocalypse Someday 二分答案+数位DP

这题应该是POJ最强大的一道数位DP了吧 正解是AC自动机 不会 还是写数位DP吧 题目大意:我们令含有666的数字为不吉利数字,则可以得到一个递增数列: {an}=666,1666,2666,3666,4666,5666,6660,6661,.... 给定n,求an 首先我们把这个问题转化成另一个问题:给定n,求1~n中有多少个数含有666 解决了这个问题,把原问题二分答案即可 首先预处理f数组,令 f[i][0]表示i位数中首位不为6且不含666的数的数量 f[i][1]表示i位数中首位连续

POJ 3208 Apocalypse Someday(数位dp)

题意:输出第n个包含连续三个6的数 思路: dp[i][0]表示i位数中首位不为6且不含666的数的数量 dp[i][1]表示i位数中首位连续1个6并且不含666的数的数量 dp[i][2]表示i位数中首位连续2个6并且不含666的数的数量 dp[i][3]表示i位数中含有666的数的数量 写出递推关系即可,再确定出带求的数有多少位,再从高位到低位逐次确定 //132K 16MS #include<cstdio> #include<cstring> #include<algo

Soj题目分类

-----------------------------最优化问题------------------------------------- ----------------------常规动态规划  SOJ1162 I-Keyboard  SOJ1685 Chopsticks SOJ1679 Gangsters SOJ2096 Maximum Submatrix  SOJ2111 littleken bg SOJ2142 Cow Exhibition  SOJ2505 The County

待刷题目分类

各大OJ题目归类 Posted on 2012 年 8 月 8 日 by admin ---------–最优化问题------------- --------动态规划 SOJ1162 I-Keyboard SOJ2096 Maximum Submatrix SOJ2111 littleken bg SOJ2505 The County Fair SOJ2818 QQ音速 SOJ2469 Exploring Pyramids SOJ1833 Base Numbers SOJ2009 Zeros

[转] POJ字符串分类

POJ 1002 - 487-3279(基础)http://acm.pku.edu.cn/JudgeOnline/problem?id=1002题意:略解法:二叉查找数,map,快排... POJ 1200 - Crazy Search(基础)http://acm.pku.edu.cn/JudgeOnline/problem?id=1200题意:找出不相同的子串数量,字母表大小和子串长度会给定,这题很推荐hash入门者一做解法:hash(建议karp-rabin) POJ 1204 - Word

数位DP POJ

Apocalypse Someday Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 1870   Accepted: 902 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 blockb