洛谷P4124 手机号码

传送

这题也就是条件限制多了点,也没有别的,套板子就好了
注意这里没有前导零,所以第一位是从1开始填
看注释叭

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int inf=214748364;
const ll mod=1000000007;
inline ll read()
{
    char ch=getchar();
    ll x=0;bool f=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')f=1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
ll l,r;
ll g[20][10][2][2][2][20],li[20];
int t;
void make(ll k)
{
    t=0;
    memset(g,-1,sizeof(g));
    while(k)
    {
        li[++t]=k%10;
        k/=10;
    }
}
ll dfs(int now,int lst,bool g8,bool g4,bool lim,bool maxc,int nc)
/*
   当前填到了第几位
   上一位填的啥
   有没有8
   有没有4
   是否顶上界
   有没有至少连续3个相同的数
   上一位和它前面的位形成了几个连续的相同的数(nowcnt)
*/
{
	if(!now) return maxc;
	if(!lim&&g[now][lst][g8][g4][maxc][nc]!=-1) return g[now][lst][g8][g4][maxc][nc];
	int up=lim?li[now]:9;
	ll rtn=0;
	for(int i=(now==t);i<=up;i++)
	{
		int mma=nc;
		if(g8&&i==4)continue;//有8没4
		if(g4&&i==8)continue;//有4没8
		if(i==lst)
		{
			mma++;
			if(nc==0)mma++;//因为一旦出现这一位与上一位相同,且上一位和上上位不相同,则产生连续两位相同的数
		}
		else mma=0;//如果与上一位不同,则说明连续的位断开,要传下去的nc变为0
		rtn+=dfs(now-1,i,g8||(i==8),g4||(i==4),lim&&(i==up),(mma>=3)||maxc,mma);
	}
	if(!lim) g[now][lst][g8][g4][maxc][nc]=rtn;
	return rtn;
}
int main()
{
   ll ans=0;
   l=read();
   r=read();
   make(r);
   ans=dfs(t,0,0,0,1,0,0);
   if(l>10000000000)//因为当l==1e10时,l-1=1e10-1,也就是说只有10位,然而dfs里面没有判位数,所以要对l=1e10进行特判(懒得在dfs里面加特判了ρωρ)
   {
   	make(l-1);
    ans-=dfs(t,0,0,0,1,0,0);
   }
   printf("%lld",ans);
}
posted @ 2019-09-08 16:32  千载煜  阅读(144)  评论(0编辑  收藏  举报