您的位置:首页 > 其它

BZOJ 1026 [SCOI2009]windy数 - 数位DP

2017-08-27 01:41 423 查看
今天才学了数位DP,好开森,迫不及待地开始写题,写了一遍又一遍输出全是0,发现原来是函数没调用(233)

一道裸的数位dp题,利用类似前缀和差值计算。

其中warn含义为此位以及以前的位数均濒临上限,若下一位超f数组的限制需要break(转移也很好转移,当上一位有warn标记且f[len]==i)

而f数组则是给定数的每一位,即枚举的最大值。

由于位数不齐,所以需要利用start枚举开始的位数(递推则是此位start标记为假,当且仅当上一位标记为假且此位为0).

差值为2的解决方法则是,若有start标记且abs<2则continue。

切记切记dp数组在计算时要归0。

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

int n,l,r,ans,totlen;
int f[20];
int dp[20][2][15][2];

void init(int x)
{
while(x)f[++totlen]=x%10,x/=10;
}
int Search(int len,bool warn,int last,bool start)
{
int &res=dp[len][warn][last][start];

if(res!=-1)return res;
if(len==0)return res=1;

res=0;

for(int i=0;i<10;i++)
{
if(warn&&i>f[len])break;
bool nextstart=true,nextwarn;

if(!start&&i==0)nextstart=false;
if(abs(last-i)<2&&start)continue;

nextwarn=(warn&&(i==f[len]))?true:false;

res+=Search(len-1,nextwarn,i,nextstart);
}
return res;
}
int main()
{
scanf("%d%d",&l,&r);

memset(dp,-1,sizeof dp);
totlen=0;
init(r);
ans+=Search(totlen,1,0,0);

memset(dp,-1,sizeof dp);
totlen=0;
init(--l);
ans-=Search(totlen,1,0,0);

printf("%d",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: