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位数中首位连续1个6并且不含666的数的数量

f[i][2]表示i位数中首位连续2个6并且不含666的数的数量

f[i][3]表示i位数中含有666的数的数量

于是我们有递推式

f[i][0]=(f[i-1][0]+f[i-1][1]+f[i-1][2])*9;

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

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

f[i][3]=f[i-1][3]*10+f[i-1][2];

然后数位DP即可

其中处理的时候要记录当前确定数字末尾的6的个数 以及确定数字中是否含有666

此外实在想吐槽一开始写错了居然跑出了样例,最奇葩的是样例中所有的6都变成了9,看到结果直接笑岔气0.0

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int f[20][4];
/*
f[i][0]表示i位数中首位不为6且不含666的数的数量
f[i][1]表示i位数中首位连续1个6并且不含666的数的数量
f[i][2]表示i位数中首位连续2个6并且不含666的数的数量
f[i][3]表示i位数中含有666的数的数量
*/
int getans(ll x)
{
	int i,j,cnt=0,re=0;
	ll tens=1,y=0;
	for(i=0;tens<x;tens*=10,i++);
	while(y<x)
	{
		int _cnt;
		while(y+tens<=x)
		{
			y+=tens;
			if(cnt==3)
				_cnt=3;
			else if(y/tens%10==7)
				_cnt=cnt+1;
			else
				_cnt=0;
			for(j=3;j>=3-_cnt;j--)
				re+=f[i][j];
		}
		if(cnt!=3)
			cnt=(y/tens%10==6?cnt+1:0);
		i--;tens/=10;
	}
	return re;
}
ll divide(ll l,ll r,int v)
{
	ll mid=l+r>>1;
	if(l+1==r)
	{
		if( getans(r)==v )
			return l;
		return r;
	}
	if( getans(mid+1)>=v )
		return divide(l,mid,v);
	else
		return divide(mid,r,v);
}
int main()
{
	int T,i,x;
	f[0][0]=1;
	for(i=1;i<=10;i++)
	{
		f[i][0]=(f[i-1][0]+f[i-1][1]+f[i-1][2])*9;
		f[i][1]=f[i-1][0];
		f[i][2]=f[i-1][1];
		f[i][3]=f[i-1][3]*10+f[i-1][2];
	}
	for(cin>>T;T;T--)
	{
		scanf("%d",&x);
		printf("%I64d\n", divide(0,10000000000ll,x) );
	}
}
时间: 2024-11-05 20:02:20

POJ 3208 Apocalypse Someday 二分答案+数位DP的相关文章

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)

题意:输出第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

TOJ 2294 POJ 3286 How many 0&#39;s? 数位dp

http://acm.tju.edu.cn/toj/showp2294.html http://poj.org/problem?id=3284 题外话:集训结束,回学校了.在宿舍看了这题,没什么好想法,去洗澡了.转了两个澡堂都特么没开..倒是在路上把这题想了.用回自己的电脑,不得不说苹果的字体渲染,真心高一个等级. 题意:给定两个数a和b,从a写到b,问一共写了多少个0. 分析:当然先转化为求0..a写多少个0.网上有更简单的做法,就是枚举每位作为0,则如果这一位本来是0,左边取1..a-1(不

POJ 3258 River Hopscotch 二分答案

River Hopscotch Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6193   Accepted: 2685 Description Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. T

POJ 2112 Optimal Milking 二分答案+最大流

首先二分最长的边,然后删去所有比当前枚举的值长的边,算最大流,看是否能满足所有的牛都能找到挤奶的地方 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include

POJ 3273 Monthly Expense 二分答案

Monthly Expense Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13281   Accepted: 5362 Description Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and r

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 3484 Showstopper(二分答案)

[题目链接] http://poj.org/problem?id=3484 [题目大意] 给出n个等差数列的首项末项和公差.求在数列中出现奇数次的数.题目保证至多只有一个数符合要求. [题解] 因为只有一个数符合要求,所以在数列中数出现次数的前缀和必定有奇偶分界线, 所以我们二分答案,计算前缀和的奇偶性进行判断,得到该数的位置. [代码] #include <cstdio> #include <algorithm> #include <cstring> using na

POJ 3579 Median(二分答案+Two pointers)

[题目链接] http://poj.org/problem?id=3579 [题目大意] 给出一个数列,求两两差值绝对值的中位数. [题解] 因为如果直接计算中位数的话,数量过于庞大,难以有效计算, 所以考虑二分答案,对于假定的数据,判断是否能成为中位数 此外还要使得答案尽可能小,因为最小的满足是中位数的答案,才会是原差值数列中出现过的数 对于判定是不是差值的中位数的过程,我们用尺取法实现. 对于差值类的题目,还应注意考虑边界,即数列只有一位数的情况. [代码] #include <cstdio