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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的数。
思路:数位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<cstring>
#include<cstdio>
#include<iostream>
#include<map>
#include<algorithm>
#include<queue>
using namespace std;
#define P pair<int,int>
#define ms(x,y) memset(x,y,sizeof x)
#define LL long long
const int maxn = 1005;
const int mod = 1e9+7;
const int maxnode = 100000*6+10;
const int sigma_size = 26;
const LL inf = 1e18;
int digit[22];
LL dp[22][5];///0表示前导0,1表示前缀一个6,2表示前缀2个6,3表示前缀3个6,4表示前缀不是6;
int next_state(int state,int x)
{
    if(state==3) return 3;
    if(x==6){
        if(state==1||state==2) return state+1;
        else return 1;
    }else
    {
        return 4;
    }
}
LL dfs(int len,int state,int bounded)
{
    if(len==0){
        return state==3;
    }
    if(!bounded&&dp[len][state]!=-1) return dp[len][state];
    int d = bounded?digit[len]:9;
    LL ans = 0;
    for(int i = 0; i <= d; i++){
        if(state==0){
            if(i==0) ans += dfs(len-1,0,bounded&&(i==d));
            else ans += dfs(len-1,i==6?1:4,bounded&&(i==d));
        }else
        {
            ans += dfs(len-1,next_state(state,i),bounded&&(i==d));
        }
    }
    if(!bounded){
        dp[len][state] = ans;
    }
    return ans;
}
LL solve(LL n)
{
    int len = 0;
    while(n){
        digit[++len] = n%10;
        n /= 10;
    }
    return dfs(len,0,true);
}
int main()
{
    int T;
    ms(dp,-1);
    cin>>T;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        LL lo = 1, hi = inf, mi;
        while(lo<hi){
            mi = (lo+hi)/2;
            LL ans = solve(mi);
            if(ans>=n){///找下界。
                hi = mi;
            }else
            {
                lo = mi+1;
            }
        }
        printf("%lld\n",hi);
    }
    return 0;
}

/*

*/

 

以上是关于poj3208 Apocalypse Someday 数位dp+二分 求第K(K <= 5*107)个有连续3个6的数。的主要内容,如果未能解决你的问题,请参考以下文章

POJ 3689 Apocalypse Someday [数位DP]

POJ 3208 启示录

poj3208启示录——数位DP

ATOM出品 — APOCALYPSE RDTA启示录雾化器评测

前端学习(3208):react中的事件绑定

bzoj3208: 花神的秒题计划Ⅰ