BZOJ 1026 [SCOI2009]windy数

来源:互联网 发布:钓鱼台工作 知乎 编辑:程序博客网 时间:2024/04/27 07:16

今天才学了数位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;}