【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)

题意:

多组数据,每组求第n个包含‘666’的数(不能断开),如1:666,2:1666,14:6667。

题解:

AC自动机解法没去想,数位DP没学,这里有一种类似于数位DP,却又与数位DP不同,我称为数位树。

数位树:

将数n如线段树一样地拆分成多个小段,进行递归处理得出答案。

本题详(lue)解:

直接看每一位应该是什么数,然后n减去相应的数,使得在下一层转换为子问题“在开头有b个连续的6时,求第a个带‘666’的数”。就是如此简单,如此简单!!!!

代码来啦!

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 20/*数的最大保证位数*/
using namespace std;
long long n;
long long f0[N],f1[N],f2[N],f3[N];
long long f10[N],f5[N],f6[4][N];
/*
注一:[N]处为位数
注二:这里说的数不去首位0,即0066算4位数

f0:首位不为6且不含‘666’的数的个数
f1:首位  为6且不含‘666’的数的个数(第二位不为‘6’)
f2:首位  为6且不含‘666’的数的个数(第二位  为‘6’)
f3:含‘666’的数的个数

f5:5开头的含‘666’的数的个数
f6:1:开头含‘6’的数的个数
	2:开头含‘66’的数的个数
	3:含‘666’的数的个数
f10:同f3
*/
long long power(long long x,long long p)
{
	long long ans=1;
	while(p>0)
	{
		if(p&1)ans*=x;
		x*=x;
		p>>=1;
	}
	return ans;
}

void dfs(long long nn,long long nm)/*位数,已连续的6的个数*/
{
	if(!nn)/*没有位了,结束!*/
	{
		printf("\n");
		return ;
	}
	long long i,j,k;
	if(nm>=3)/*剪枝(如果前面已经‘666’了,那么直接算数就好)*/
	{
		long long tens=1;
		n--;
		for(i=1;tens<=n;i++,tens*=10);
		for(;i<=nn;i++)printf("0");
		if(n)printf("%I64d",n);
		printf("\n");
		return ;
	}
	if(f5[nn]>=n)/*此位为0~5*/
	{
		printf("%I64d",(n-1)/f10[nn-1]);
		n=(n-1)%f10[nn-1]+1;
		dfs(nn-1,0);
		return ;
	}
	else if(f6[3-nm][nn]>=n)/*此位为6*/
	{
		printf("6");
		n-=f5[nn];
		dfs(nn-1,nm+1);
		return ;
	}
	else/*此位为7~9*/
	{
		n-=f6[3-nm][nn];
		printf("%I64d",(n-1)/f10[nn-1]+7);
		n=(n-1)%f10[nn-1]+1;
		dfs(nn-1,0);
		return ;
	}
}

void init()/*预处理*/
{
	long long i;
	f0[0]=1;
	for(i=1;i<N;i++)
	{
		f0[i]=(f0[i-1]+f1[i-1]+f2[i-1])*9;
		f1[i]=f0[i-1];
		f2[i]=f1[i-1];
		f3[i]=f3[i-1]*10+f2[i-1];
	}
	for(i=3;i<N;i++)/*i位数中含‘666’的数的个数*/
	{
		f10[i]=f3[i];
		f5[i]=6*f10[i-1];
		f6[3][i]=f10[i]-3*f10[i-1];
		f6[2][i-1]=f6[3][i]-f5[i]-3*f10[i-2];
		f6[1][i-2]=f6[2][i-1]-f5[i-1]-3*f10[i-3];
	}
}

int main()
{
	long long i,g;
	scanf("%I64d",&g);
	init();
	while(g--)
	{
		scanf("%I64d",&n);
		for(i=3;f10[i]<n;i++);
		dfs(i,0);
	}
	return 0;
}
时间: 2024-10-12 10:38:51

【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)的相关文章

[dp专题] AC自动机与状态压缩dp的结合

最近做到好几道关于AC自动机与状态压缩dp的结合的题,这里总结一下. 题目一般会给出m个字符串,m不超过10,然后求长度为len并且包含特定给出的字符串集合的字符串个数. 以HDU 4758为例: 把题意抽象为:给出两个字符串,且只包含两种字符 'R'.'D',现在求满足下列条件的字符串个数:字符串长度为(m+n),其中包含n个'D',m个'R'. 如果不用AC自动机来做,这道题还真没法做了,因为不管怎样都找不到正确的dp状态转移方程. 而如果引入AC自动机,把在AC自动机上的结点当做dp的一个

HDU 3247 Resource Archiver (AC自动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串,m个病毒串,问包含所有正常串(可重叠)且不包含任何病毒串的字符串的最小长度为多少. AC自动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.可以优化很多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using n

[BZOJ 1009] [HNOI2008] GT考试 【AC自动机 + 矩阵乘法优化DP】

题目链接:BZOJ - 1009 题目分析 题目要求求出不包含给定字符串的长度为 n 的字符串的数量. 既然这样,应该就是 KMP + DP ,用 f[i][j] 表示长度为 i ,匹配到模式串第 j 位的字符串个数,然后转移就是可以从第 j 位加上一个字符转移到另一个位置. 然而..我并没有写过KMP + DP,我觉得还是写AC自动机+DP比较简单..于是,尽管只有一个模式串,我还是写了AC自动机+DP. 然后就是建出AC自动机,f[i][j] 表示长度为 i ,走到节点 j 的字符串的个数.

【HDU2825】Wireless Password【AC自动机,状态压缩DP】

题意 题目给出m(m<=10)个单词,每个单词的长度不超过10且仅由小写字母组成,给出一个正整数n(n<=25)和正整数k,问有多少方法可以组成长度为n的文本且最少包含k个给出的单词. 分析 和上一个AC自动机很相似,上一篇博客是不包含任何一个单词长度为n的方案数,这个题是包含至少k个单词的方案数,而且n,m,k都非常的小. 按照前面的经验很容易想到,我们还是得先建一个AC自动机,然后把它的单词结点标记出来.与前面不同的是我们在状态转移的时候需要考虑到当前走过的结点已经包含多少单词了.所以我们

HDU 3247 Resource Archiver AC自动机 + bfs + 状态压缩dp

题意:给定你n个文本串 ,m个模式串,怎么构造最短的新的文本串使得这个新的文本串包含n个文本串的所有信息且文本串的长度最短且不包含模式串. 解题思路:这里看题解撸的,首先我们算出两两文本串的距离(end数组标记文本和模式串的值不同,利用这个进行bfs算出两两之间的最短距离,注意到这里模式串的end是不能走到的.这里也不需要松弛操作),然后因为n只有10这么大,所以我们可以状态压缩  ,dp[i][j] 表示 压缩后状态为 i(二进制压缩,每i位表示第i个是否在)且 以j结尾的文本串的最小花费.这

[AC自动机+spfa+状压dp] hdu 3247 Resource Archiver

题意: 给n个本源串,m个病毒串 求一个最多的长度的单词包含所有的本源串并不包含任意一个病毒串 串均为01串 思路: 只有10个本源串 一开始想的是直接建立完trie图 然后在图上直接spfa 结果发现 dis[60005][1030] 超内存了 这个时候就要想到 其实只有节点的mark值大于0的节点是我们需要用的 就是那些含有状压权值的节点 那么我们先记录下这些节点是哪些 然后发现其实这些不到100个节点 所以跑100遍spfa 求出两两之间的最短路 然后用这个距离 去状压dp 数组就成了 d

18.10.29 POJ 3987 Computer Virus on Planet Pandora(AC自动机+字符串处理)

描述 Aliens on planet Pandora also write computer programs like us. Their programs only consist of capital letters (‘A’ to ‘Z’) which they learned from the Earth. On planet Pandora, hackers make computer virus, so they also have anti-virus software. Of

poj 1699 Best Sequence(AC自动机+状压DP)

题目链接:poj 1699 Best Sequence 题目大意:给定N个DNA序列,问说最少多长的字符串包含所有序列. 解题思路:AC自动机+状压DP,先对字符串构造AC自动机,然后在dp[s][i]表示匹配了s,移动到节点i时候的最短步数. #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include &

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契