题意:问你在所有包含666的数中,第n大的是多少。(1 ≤ n ≤ 50,000,000) 。开头几个是666, 1666, 2666, 3666, 4666, 5666…

题解:

这题可以用AC自动机,不知道这个怎么做。。

用了数位DP。

第一道自己好好调出来的数位DP。。哭泣

(一)先用DP预处理出含有666的k位数一共有多少个,不含有666的k位数一共有多少个。只用求一边就可以,另一边用总数来减。

然后for一遍,判断出第n大的是多少位数。

//d[0][i] 第一位不是6的i位数不含666总方案数
//d[1][i] 第一位是6...
//d[2][i] 连续两个6...
//d[3][i] 不含666的i位数的总方案数
//d[4][i] 含有666的i位数...

(二)填数(从左往右)。填的时候要记录前两位是什么。

分两种情况:

1.填的数中已经有666。则后面的位可以填有666和没有666的数。

2.没有666。

这个再分两种 (1)现在不要填6-->则后面必须有666

(2)现在填6  如果是xx6,则后面可以是66xxxx或含有666的数;如果是x66,则后面是6xxx或者66xxx或者含有666的数。如果是xx6,则后面是66xxx或者含有666的数。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std; typedef long long LL;
const int N=,D=;
LL d[][];
int n,ans[];
//d[0][i] 第一位不是6的i位数不含666总方案数
//d[1][i] 第一位是6...
//d[2][i] 连续两个6...
//d[3][i] 不含666的i位数的总方案数
//d[4][i] 含有666的i位数... int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
memset(d,,sizeof(d));
memset(ans,,sizeof(ans));
LL sum=;
d[][]=;d[][]=;d[][]=;d[][]=;d[][]=;
d[][]=*;d[][]=;d[][]=;d[][]=*;d[][]=;
for(int i=;i<=D;i++)
{
d[][i]=*d[][i-];
d[][i]=d[][i-];
d[][i]=d[][i-];
d[][i]=d[][i]+d[][i]+d[][i];
sum*=;
d[][i]=sum-d[][i];
}
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int k=;
for(LL i=;i<=D;i++)
if(d[][i]>n) {k=i;break;}
int now=,a=,b=;
bool ok=;
for(int i=;i<=k;i++)
{
if(i==k)
{
if(!ok) ans[k]=;
else ans[k]=n-now-;
break;
}
bool bk=;
for(int j=;j<=;j++)
{
if(!ok)
{
if(j!=)
{
if(now+d[][k-i]<n) now+=d[][k-i];
else ans[i]=j,bk=;
}
else
{
if(a== && b==)
{
if(now+d[][k-i]+d[][k-i]<n) now+=d[][k-i]+d[][k-i];
else ans[i]=j,bk=,ok=;
}
else if(a!= && b==)
{
if(now+d[][k-i]+d[][k-i]+d[][k-i]<n) now+=d[][k-i]+d[][k-i]+d[][k-i];
else ans[i]=j,bk=;
}
else //这里原本打了a、b都不等于6,WA,应该是b不等于6就可以了。
{
if(now+d[][k-i]+d[][k-i]<n) now+=d[][k-i]+d[][k-i];
else ans[i]=j,bk=;
}
}
}
else
{
if(now+d[][k-i]+d[][k-i]<n) now+=d[][k-i]+d[][k-i];
else ans[i]=j,bk=;
}
if(bk) break;
}
a=ans[i-],b=ans[i];
}
bool fir=;
for(int i=;i<=k;i++)
{
if(fir== && ans[i]==) continue;
if(fir== && ans[i]!=) fir=;
if(fir) printf("%d",ans[i]);
}
if(T) printf("\n");
}
return ;
}

【poj3208-Apocalypse Someday】数位DP的更多相关文章

  1. 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的数. ...

  2. poj3208 Apocalypse Someday[数位DP]

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

  3. POJ 3689 Apocalypse Someday [数位DP]

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

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

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

  5. POJ3208 Apocalypse Someday

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

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

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

  7. POJ 3208-Apocalypse Someday(数位dp)

    题意:给定n,输出第n大包含666的数字. 分析:dp[i][j][k][l]表示 长度为i,当前位是否是6,前一位是否6,是否已经包含666,表示的数量,再用二分找出第n大的这样的数字. #incl ...

  8. 数位DP专题

    这周开始刷数位DP,在网上找到一份神级数位DP模板,做起题目来爽歪歪. http://www.cnblogs.com/jffifa/archive/2012/08/17/2644847.html in ...

  9. 开坑数位dp

    [背景] 在10月3日的dp专练中,压轴的第6题是一道数位dp,于是各种懵逼. 为了填上这个留存已久的坑,蒟蒻chty只能开坑数位dp了. [例题一][HDU2089]不要62 题目大意:给你一个区间 ...

  10. 数位dp真·浅谈 By cellur925

    预警:由于是从$Vergil$学长那里和$Mathison$大神那里学来的,所以清一色记忆化搜索!qwq 巨佬的数位dp讲解(未来的咕咕日报头条): https://www.luogu.org/blo ...

随机推荐

  1. 如何在ios 系统 中抓包??

    为了实现在ios系统上抓包,如下步骤: 1,设备越狱 2,在cydia-软件源-设置中改为开发者,否则有些deb搜索不到 安装如下软件:OpenSSH,OpenSSL,wget (下载工具) Apti ...

  2. java中字符串String 转 int(转)

    java中字符串String 转 int String -> int s="12345"; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法 ...

  3. Java Day 11

    异常 Throwable 子类 Error.Exception  Error - 不可以处理 Exception - 针对性处理 原理 自定义异常 异常类的抛出throws 先检查语法错误,后检查逻辑 ...

  4. JAVA栈实例—括号匹配

    import java.util.Stack; public class test { public static void main(String[] args){ System.out.print ...

  5. [shell基础]——sed命令

    关于sed sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓 ...

  6. Windows下安装Cygwin

    1.去官网下载Cygwin http://www.cygwin.com/ 注意32位和64位的选择,完了直接点击exe文件开始安装. 2.安装 (1)“下一步”: (2)“Install form I ...

  7. 使用VBA实现Excel自杀功能

    曾经看到过一个“Excel-Home”出品的“关于Excel自杀功能”的视频教程,经认真学习后,我写下了自己的代码,分享于此. 实现思路: 使用VBA创建一个隐藏的名称,记录当前工作簿打开的次数,如果 ...

  8. 微软职位内部推荐-Software Engineer II-Web app

    微软近期Open的职位: The Office App Services team is working on the powerful Office Web Apps including Word ...

  9. 再论 ASP.NET 中获取客户端IP地址

    说到IP获取无非是我们常见的以下几种方式,但是具体获取的值具体区别在哪?网上不乏相关文章,说的也是很详细,但是真正使用起来,还有很多不太对的地方.IP在不同系统中,应用相当广泛,常见的日志记录.广告分 ...

  10. 第六周博客技术发表 C语言代码

    #include <stdio.h>       /*使用printf要包含的头文件*/#include <conio.h>void main(void)        /*主 ...