BZOJ 1026 SCOI2009 windy数 数位DP

题目大意:求[a,b]区间内有多少个数满足任意相邻两个位置上的数>=2

首先将[a,b]分解为[1,b]-[1,a-1]

然后令f[i][j]为以i开头的j位windy数有多少个

然后十进制拆分即可

此题有些要讨论的地方:

1.小心爆int

2.最后一位要单独讨论

3.已经确定的数字是否不满足windy数的条件

4.一开始的[0,99...99]的区间需要单独计算

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int f[10][20];//f[i][j]表示以i开头的j位windy数有多少  
bool Conflict(int x)
{
	int temp=-10;
	while(x)
	{
		if(abs(temp-x%10)<2)
			return true;
		temp=x%10;x/=10;
	}
	return false;
}
int Digital_DP(ll x)
{
	int i,j,re=0;
	ll pos,now;
	for(i=1,pos=10;pos<=x;i++,pos*=10)
	{
		for(j=1;j<=9;j++)
			re+=f[j][i];
	}
	now=pos/=10;--i;
	while(now<x)
	{
		while(now+pos<=x)
		{
			int temp=now/pos%10;
			if( !Conflict(now/pos) )
				for(j=0;j<=9;j++)
					if(abs(j-temp)>=2||pos==1)
						re+=f[j][i];
			now+=pos;
		}
		if( Conflict(now/pos) )
			break;
		pos/=10;--i;
		
	}
	return re;
}
int main()
{
	int i,j,k;
	f[0][0]=1;
	for(i=0;i<=9;i++)
		f[i][1]=1;
	for(j=2;j<=10;j++)
		for(i=0;i<=9;i++)
			for(k=0;k<=9;k++)
				if(abs(i-k)>=2)
					f[i][j]+=f[k][j-1];
	int a,b;
	cin>>a>>b;
	cout<<Digital_DP(b+1)-Digital_DP(a)<<endl;
}


BZOJ 1026 SCOI2009 windy数 数位DP

上一篇:Delphi 之 菜单组件(TMainMenu)


下一篇:c# winfrom 菜单中快捷键的设置