[CQOI2016]手机号码

Posted chinesepikaync

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2016]手机号码相关的知识,希望对你有一定的参考价值。

非常模板的数位dp

状态 (f_{dep,status,fe})

我们用 (status) 来记录“要出现至少 3 个相邻的相同数字” 这个限制

(status=0) ,说明还没初始化

(status=30) ,说明已经满足了这个限制

剩下的 (status=overline{xy}) (即 (status=10 imes x+y) ) ,表示出现了连续 (x)(y)

例子:(status=25) 说明出现了连续 (2)(5)

然后 (fe) 来记录“号码中不能同时出现 8 和 4” 这个限制

(fe) 的二进制位从左往右第 1 位记录 4 是否出现过,第 2 位记录 8 是否出现过

例子:(status=2) (即二进制 (10) )表示没有出现过 4 但是出现过 8

关于不能有前导 0 ,在枚举数字的时候判断如果正在枚举首位那就不枚举 0

然后就是愉快的套个模板,提交,AC!

注意,如果出现 (L=10^{10}) 这种毒瘤数据要特判,直接把 (L-1) 跑数位dp就会挂

其他数位dp的题也要注意一下这种边界条件的问题

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define int long long
using namespace std;
template <class t> inline void read(t &s)
{
	s=0;
	reg int f=1;
	reg char c=getchar();
	while(!isdigit(c))
	{
		if(c==‘-‘)
			f=-1;
		c=getchar();
	}
	while(isdigit(c))
		s=(s<<3)+(s<<1)+(c^48),c=getchar();
	s*=f;
	return;
}
int f[12][31][4];
int num[100],n;
inline int dfs(int dep,int status,int fe,bool limit)
{
	// fe 00: no 4 or 8 ; fe 01 : have 4 but no 8, fe 10 : have 8 but no 4; fe 11 have 4 and 8
	// status : 30 is finally ; xy means the number of y is x
	if(!dep)
		return (status==30&&fe!=3)?1:0;
	if(!limit&&~f[dep][status][fe])
		return f[dep][status][fe];
	
//	printf("%d %d %d %d
",dep,status,fe,limit);

	reg int maxi=limit?num[dep]:9,res=0;
	for(int i=0;i<=maxi;++i)
	{
		if(dep==n&&!i)
			continue;
		reg int nstatus=status,nfe=fe;
		if(!status)
			nstatus=10+i;
		else if(status!=30)
		{
			if(status%10==i)
			{
				if(status/10==1)
					nstatus=20+i;
				else
					nstatus=30;
			}
			else
				nstatus=10+i;
		}
		if(i==4)
			nfe|=1;
		else if(i==8)
			nfe|=2;
		res+=dfs(dep-1,nstatus,nfe,limit&&i==maxi);
	}
	if(!limit)
		f[dep][status][fe]=res;
	return res;
}
inline int solve(int x)
{
	memset(f,-1,sizeof f);
	n=0;
	while(x)
		num[++n]=x%10,x/=10;
	return dfs(n,0,0,true);
}
signed main(void)
{
	reg int extra=0;
	int L,R;cin>>L>>R;
	if(L==10000000000ll)
		++L,++extra;
	cout<<solve(R)-solve(L-1)+extra<<endl;
	return 0;
}

以上是关于[CQOI2016]手机号码的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 4521 CQOI 2016 手机号码 数位DP

[CQOI2016]手机号码

Bzoj4521 [Cqoi2016]手机号码

luogu4124bzoj4521 [CQOI2016]手机号码 [数位dp]

P4124 [CQOI2016]手机号码

bzoj4521: [Cqoi2016]手机号码