1026: [SCOI2009]windy数 (按位DP)

定义windy数:相邻数字的差至少是2的数,例如10不是windy数,而13是windy数。求给定区间中有多少windy数。区间端点范围为 [1, 2000000000]

dfs写法
#include <stdio.h>
#include <string.h>
#define N 10
int dp[N][N],digit[N];
int dfs(int pos,int last,int z,int f)
{
    if(pos==-1) return 1;
    if(z&&!f&&dp[pos][last]!=-1)    return dp[pos][last];

    int max=f?digit[pos]:9;
    int ret=0;
    if(z==0)
    {
        for(int i=0;i<=max;i++)
        {
            ret+=dfs(pos-1,i,i,f&&i==max);
        }
    }
    else
    {
        for(int i=0;i<=max;i++)
        {
            if((i-last)*(i-last)<4) continue;
            ret+=dfs(pos-1,i,1,f&&i==max);
        }
    }
    if(z&&!f)   dp[pos][last]=ret;
    return ret;
}
int cal(int x)
{
    int pos=0;
    while(x)
    {
        digit[pos++]=x%10;
        x/=10;
    }
    return dfs(pos-1,0,0,1);
}
int main()
{
    memset(dp,-1,sizeof(dp));
    int a,b;
    while(~scanf("%d%d",&a,&b)) printf("%d\n",cal(b)-cal(a-1));
    return 0;
}
递推写法
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define LEN 15
char a[LEN],b[LEN];
int n,m;
int dp[LEN][10][2][2][2];       //第二维记录最后的数字,第三维记录状态是否合法,第四维记录该位是否是最高位,最后一维记录是否达到上界
int nextstate(int cur,int last,int in)
{
    if(cur==0 && abs(last-in)>=2)   return 0;
    return 1;
}
int nextflag1(int cur,int in,int max)
{
    if(cur==1 && in==max)   return 1;
    if(cur==1 && in>max)    return -1;
    return 0;
}
int nextflag2(int cur,int in)
{
    if(cur==1 && in==0) return 1;
    return 0;
}
int DP(char *s,int len)
{
    memset(dp,0,sizeof(dp));
    dp[0][0][0][1][1]=1;
    for(int i=1;i<=len;i++)
        for(int last=9;last>=0;last--)
            for(int state=0;state<2;state++)
                for(int flag1=0;flag1<2;flag1++)
                    for(int flag2=0;flag2<2;flag2++)
                        for(int in=0;in<10;in++)
                        {
                            int nxt=nextstate(state,last,in);
                            if(flag2==1)    nxt=0;
                            if(nextflag1(flag1,in,s[i]-'0')!=-1)
                                dp[i][in][nxt][nextflag1(flag1,in,s[i]-'0')][nextflag2(flag2,in)]+=dp[i-1][last][state][flag1][flag2];
                        }
    int ret=0;
    for(int i=0;i<10;i++)   ret+=dp[len][i][0][0][0]+dp[len][i][0][1][0];
    return ret;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        n--;
        sprintf(a+1,"%d",n);
        sprintf(b+1,"%d",m);
        printf("%d\n",DP(b,strlen(b+1))-DP(a,strlen(a+1)));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/algorithms/p/2620431.html