【BZOJ4521】【CQOI2016】手机号码 数位DP

【BZOJ4521】【CQOI2016】手机号码 数位DP_第1张图片

所以说CQOI板子背少了没人权。。。Day1唯一A了的题目

题目非常良心的帮人们略去了前导零的烦恼,给定的范围一定是十一位的整数,但这同时意味着裸对拍真!的!好!慢!

设状态DP(i,j,k,ok1,ok2)表示前i位最后一位是j倒数第二位是k,ok1记录是否已经有三连续,ok2记录4和8出现的情况(不能同时出现所以可以压到一位),再加上一堆奇奇怪怪的细节,递推思路倒是比较清晰。

注意如果他上界给的99999999999(差不多就是这么多个)我们计算时一进位就会出事。。。记得特判一下(我也不知道有没有这种数据)

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
long long L,R;
int a[15],ct;

long long dp[15][15][15][5][5];
void ready()
{
	memset(dp,0,sizeof(dp));
	dp[0][0][0][0][0]=1;
	for(int i=0;i<11;i++)//少年你怕了吗
	{
		for(int j=0;j<=9;j++)
		{
			for(int k=0;k<=9;k++)
			{
				for(int u=0;u<=1;u++)
				{
					for(int v=0;v<=2;v++)if(dp[i][j][k][u][v])
					{
						for(int w=0;w<=9;w++)
						{
							if(v==1 && w==8)continue;
							if(v==2 && w==4)continue;
							if(i>=2 && w==j && j==k)
							{
								if(w==4)
								{
									dp[i+1][w][j][1][1]+=dp[i][j][k][u][v];
								}
								else if(w==8)
								{
									dp[i+1][w][j][1][2]+=dp[i][j][k][u][v];
								}
								else
								{
									dp[i+1][w][j][1][v]+=dp[i][j][k][u][v];
								}
							}
							else
							{
								if(w==4)
								{
									dp[i+1][w][j][u][1]+=dp[i][j][k][u][v];
								}
								else if(w==8)
								{
									dp[i+1][w][j][u][2]+=dp[i][j][k][u][v];
								}
								else
								{
									dp[i+1][w][j][u][v]+=dp[i][j][k][u][v];
								}
							}
						}
					}
				}
			}
		}
	}
	return ;
}
long long f(long long x)
{
	ct=0; while(x){a[++ct]=x%10; x=x/10;}
	if(ct==10)return 0;
	long long ans=0;
	int c=0,w=0;
	if(ct==12)
	{
		for(int i=1;i<=9;i++)
		{
			for(int j=0;j<=9;j++)
			{
				ans+=dp[11][i][j][1][0];
				ans+=dp[11][i][j][1][1];
				ans+=dp[11][i][j][1][2];
			}
		}
		return ans;
	}
	for(int i=ct;i>=1;i--)
	{
		if(i==ct)
		{
			for(int j=1;j<a[i];j++)
			{
				for(int k=0;k<=9;k++)
				{
					ans+=dp[i][j][k][1][0];
					ans+=dp[i][j][k][1][1];
					ans+=dp[i][j][k][1][2];
				}
			}
		}
		else
		{
			if(w==1)
			{
				for(int j=0;j<a[i];j++)
				{
					if(c==1 && j==8)continue;
					if(c==2 && j==4)continue;

					for(int k=0;k<=9;k++)
					{
						if(c==1 && k==8)continue;
						if(c==2 && k==4)continue;
						ans+=dp[i][j][k][0][0];
						if(c!=2)ans+=dp[i][j][k][0][1];
						if(c!=1)ans+=dp[i][j][k][0][2];
							
						ans+=dp[i][j][k][1][0];
						if(c!=2)ans+=dp[i][j][k][1][1];
						if(c!=1)ans+=dp[i][j][k][1][2];
					}
				}
			}
			else if(i<=ct-2 && a[i+2]==a[i+1])
			{
				for(int j=0;j<a[i];j++)
				{
					if(c==1 && j==8)continue;
					if(c==2 && j==4)continue;
					if(j==a[i+1])
					{
						for(int k=0;k<=9;k++)
						{
							if(c==1 && k==8)continue;
							if(c==2 && k==4)continue;
							ans+=dp[i][j][k][0][0];
							if(c!=2)ans+=dp[i][j][k][0][1];
							if(c!=1)ans+=dp[i][j][k][0][2];
							
							ans+=dp[i][j][k][1][0];
							if(c!=2)ans+=dp[i][j][k][1][1];
							if(c!=1)ans+=dp[i][j][k][1][2];
						}
					}
					else
					{
						for(int k=0;k<=9;k++)
						{
							if(c==1 && k==8)continue;
							if(c==2 && k==4)continue;
							ans+=dp[i][j][k][1][0];
							if(c!=2)ans+=dp[i][j][k][1][1];
							if(c!=1)ans+=dp[i][j][k][1][2];
						}
					}
				}
			}
			else
			{
				for(int j=0;j<a[i];j++)
				{
					if(c==1 && j==8)continue;
					if(c==2 && j==4)continue;					
	
					if(j==a[i+1] && i>=2)
					{
						for(int k=0;k<=9;k++)
						{
							if(c==1 && k==8)continue;
							if(c==2 && k==4)continue;
							if(j==k)
							{
								ans+=dp[i][j][k][0][0];
								if(c!=2)ans+=dp[i][j][k][0][1];
								if(c!=1)ans+=dp[i][j][k][0][2];
								ans+=dp[i][j][k][1][0];
								if(c!=2)ans+=dp[i][j][k][1][1];
								if(c!=1)ans+=dp[i][j][k][1][2];
							}
							else
							{
								ans+=dp[i][j][k][1][0];
								if(c!=2)ans+=dp[i][j][k][1][1];
								if(c!=1)ans+=dp[i][j][k][1][2];
							}							
						}
					}
					else
					{
						for(int k=0;k<=9;k++)
						{
							if(c==1 && k==8)continue;
							if(c==2 && k==4)continue;
							ans+=dp[i][j][k][1][0];
							if(c!=2)ans+=dp[i][j][k][1][1];
							if(c!=1)ans+=dp[i][j][k][1][2];
						}
					}
					
				}
			}
		}
		if(a[i]==4)
		{
			if(c==2)break;
			c=1;
		}
		else if(a[i]==8)
		{
			if(c==1)break;
			c=2;
		}
		if(i<=ct-2 && a[i]==a[i+1] && a[i+1]==a[i+2])
		{
			w=1;
		}
	//	cout<<ans<<endl;
	}
	return ans;
}
int main()
{
	//freopen("number.in","r",stdin);
	//freopen("number.out","w",stdout);

	cin>>L>>R;

	ready();
	cout<<f(R+1)-f(L)<<endl;
	return 0;
}


你可能感兴趣的:(【BZOJ4521】【CQOI2016】手机号码 数位DP)