传送门

很神奇的一道题,正解是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

//NOIp DP apo
//by Cydiater
//2016.10.4
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <ctime>
#include <iomanip>
#include <cmath>
using namespace std;
#define ll long long
#define up(i,j,n)        for(ll i=j;i<=n;i++)
#define down(i,j,n)        for(ll i=j;i>=n;i--)
#define FILE "apo"
const ll MAXN=1e6+5;
const ll oo=0x3f3f3f3f;
const ll mod=(1<<31)-1;
inline ll read(){
    char ch=getchar();ll x=0,f=1;
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
ll f[25][10],leftt,rightt,mid,T;
namespace solution{
    void pret(){
        memset(f,0,sizeof(f));
        f[0][0]=1;
        up(i,1,21){
            f[i][3]=f[i-1][3]*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])*9;
        }
    }
    ll check(ll num){
        ll di=0,far=1,tmp=0,cnt=0,ans=0;
        for(;far<num;far*=10,di++);
        while(tmp<num){
            ll re_cnt;
            while(tmp+far<=num){
                tmp+=far;
                if(cnt==3)                    re_cnt=3;
                else if((tmp/far)%10==7)    re_cnt=cnt+1;
                else                        re_cnt=0;
                down(i,3,3-re_cnt)ans+=f[di][i];
            }
            if(cnt!=3)cnt=((tmp/far)%10==6?cnt+1:0);
            di--;far/=10;
        }
        return ans;
    }
    ll slove(ll N){
        leftt=1;rightt=100000000000000000LL;
        N--;
        while(leftt+1<rightt){
            mid=(leftt+rightt)>>1;
            ll tmp=check(mid);
            if(tmp>N)    rightt=mid;
            else        leftt=mid;
        }
        if(check(leftt)==N)    return leftt;
        return    rightt;
    }
}
int main(){
    freopen(FILE".in","r",stdin);
    //freopen(FILE".out","w",stdout);
    using namespace solution;
    pret();
    T=read();
    while(T--)cout<<slove(read())<<endl;
    return 0;
}

POJ3208:Apocalypse Someday的更多相关文章

  1. 【POJ3208】Apocalypse Someday

    Description 666号被认为是神秘的"野兽之数",在所有以启示录为主题的大片中都是一个被广泛使用的数字.但是,这个数字666不能总是在脚本中使用,所以应该使用1666这样 ...

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

    /** 题目:poj3208 Apocalypse Someday 链接:http://poj.org/problem?id=3208 题意:求第K(K <= 5*107)个有连续3个6的数. ...

  3. POJ3208 Apocalypse Someday

    题意 Language:Default Apocalypse Someday Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 2 ...

  4. POJ 3689 Apocalypse Someday [数位DP]

    Apocalypse Someday Time Limit: 1000MS   Memory Limit: 131072K Total Submissions: 1807   Accepted: 87 ...

  5. Apocalypse Someday

    Apocalypse Someday 定义一个数是合法的,当且仅当中间出现至少一个连续的大于三个的6,求第x个合法的数,\(x\leq 50,000,000\) 解 首先,注意到求第几个,即想到试填法 ...

  6. poj3208 Apocalypse Someday[数位DP]

    数位中出现至少3个连续的'6'的数字(称魔鬼数),询问满足要求的排名k的数. 经典题型.采用试填法. 递推做法:预处理出$i$位数字中满足要求的数(下记为'魔鬼数').对每一位都从0到9试一遍,然而卡 ...

  7. POJ3208 Apocalypse Someday(二分 数位DP)

    数位DP加二分 //数位dp,dfs记忆化搜索 #include<iostream> #include<cstdio> #include<cstring> usin ...

  8. POJ-3208 Apocalypse Someday (数位DP)

    只要某数字的十进制表示中有三个6相邻,则该数字为魔鬼数,求第X小的魔鬼数\(X\le 5e7\) 这一类题目可以先用DP进行预处理,再基于拼凑思想,用"试填法"求出最终的答案 \( ...

  9. POJ 3208 Apocalypse Someday

    题意: 将含有连续的三个6的数称为不吉利数,比如666,1666,6662,但是6266吉利.则666为第一个不吉利数,输入整数n,求第n个不吉利数.(n <= 5*10^7) 解法: 如果是给 ...

随机推荐

  1. 搭建emacs的go编程语言环境

    关于emacs就不说明了,直接切入主题.关于我的emacs配置,可以直接参考GitHub上的lienhua34/myemacs-conf. go-mode 安装 关于go-mode的安装,可以直接参考 ...

  2. jQuery.uploadify-----文件上传带进度条,支持多文件上传的插件

    借鉴别人总结的uploadify:基于jquery的文件上传插件,支持ajax无刷新上传,多个文件同时上传,上传进行进度显示,控制文件上传大小,删除已上传文件. uploadify有两个版本,一个用f ...

  3. vNext之旅(1):从概念和基础开始

    ASP.NET vNext or .NET vNext? vNext在曝光以来绝大多数以ASP.NET vNext这样的的字眼出现,为什么这边会提及.NET vNext?原因是我认为ASP.NET只是 ...

  4. 基于tiny4412原生uboot修改制作SD启动并烧写到emmc

    最近入手tiny4412的标准板,底板SDK型号为1506.但是因为友善之臂提供的superboot不能进入boot菜单,此时我就不能通过tftp下载内核和通过nfs挂载根文件系统,于是想自己做个ub ...

  5. Android Studio2.0 教程MAC版 -快捷键篇

    本文转至 Android Studio2.0 教程从入门到精通MAC版 - 提高篇 ( OPEN 开发经验库) 第二篇我们开发了一个Hello World应用,并介绍Android Sutdio的界面 ...

  6. Shell命令_if

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #if if [ 条件判断式 ] ...

  7. 【BZOJ 2440】【中山市选 2011】完全平方数 莫比乌斯函数+容斥原理

    网上PoPoQQQ的课件: •题目大意:求第k个无平方因子数 •无平方因子数(Square-Free Number),即分解之后所有质因数的次数都为1的数 •首先二分答案 问题转化为求[1,x]之间有 ...

  8. C#元组示例详解

    元组的概要: 数组合并了相同类型的对象,而元组合并了不同类型的对象.元组起源于函数编程语言(如F#) ,在这些语言中频繁使用元组.在N盯4中,元组可通过.NET Fmmework用于所有的NET语言. ...

  9. Struts2 Action扩展名的三种修改方法

    最近在做项目开发过程中犯了一个很低级的错误,在这里列举出来,供大家参考借鉴:我希望通过Url请求一个Action,最终通过服务器的处理能得到一个Json串,所以我在Url中体现这一特点,将action ...

  10. lightoj 1370 欧拉函数

    A - Bi-shoe and Phi-shoe Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & % ...