zoukankan      html  css  js  c++  java
  • P2657 [SCOI2009]windy数 数位dp入门

    参考了题解,理解仍然还不够透彻

    #include<bits/stdc++.h>
    using namespace std;
    const int N=550;
    const int maxn=1e6+7;
    int num[maxn];
    int dp[N][N];
    int a,b;
    int dfs(int len,int pre,bool flag,bool zero)
    {
        if(len==0)
        {
            return 1;
        }
        if(!zero&&!flag&&dp[len][pre]!=-1)
        {
            return dp[len][pre];
        }
        int p,cnt=0,maxx=(flag?num[len]:9);
        for(int i=0;i<=maxx;i++)
        {
            if(abs(i-pre)<2)
            {
                continue;
            }
            p=i;
            if(zero&&i==0)
            {
                p=-233;
            }
            cnt+=dfs(len-1,p,(flag)&&(i==maxx),(p==-233));
        }
        if(!flag&&!zero)
        {
            dp[len][pre]=cnt;
        } 
        return cnt;
    }
    int solve(int x)
    {
        int k=0;
        while(x)
        {
            num[++k]=x%10;
            x/=10;
        }
        memset(dp,-1,sizeof(dp));
        return dfs(k,-233,true,true);
    }
    int main()
    {
        scanf("%d%d",&a,&b);
        printf("%d",solve(b)-solve(a-1));
        return 0;
    } 

     还有一种更易理解的做法

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll dp[15][15],ans;//dp[i][j]表示搜到第i位,前一位是j,的!limit方案totnum;
    int a[15],len;
    long long L,R;
    ll dfs(int pos,int pre,int st,int limit)//pos当前位置,pre前一位数,st判断前面是否全是0,limit最高位限制 
    {
        if(pos>len) return 1;//搜完了 
        if(!limit&&dp[pos][pre]!=-1) return dp[pos][pre];//没有最高位限制,已经搜过了
        ll ret=0;
        int res=limit?a[len-pos+1]:9;//当前位最大数字 
        for(int i=0;i<=res;i++)//从0枚举到最大数字 
        {
            if(abs(i-pre)<2) continue;//不符合题意,继续 
            if(st&&i==0) ret+=dfs(pos+1,-2,1,limit&&i==res);//如果有前导0,下一位随意 
            else ret+=dfs(pos+1,i,0,limit&&i==res);//如果没有前导0,继续按部就班地搜 
        }
        if(!limit&&!st) dp[pos][pre]=ret;//没有最高位限制且没有前导0时记录结果 
        return ret;
    }
    void part(ll x)
    {
        len=0;
        while(x) a[++len]=x%10,x/=10;
        memset(dp,-1,sizeof dp);
        ans=dfs(1,-2,1,1);
    }
    int main()
    {
        scanf("%lld%lld",&L,&R);
        part(L-1);ll minn=ans;
        part(R);  ll maxx=ans;
        printf("%lld",maxx-minn);
        return 0;
    }
  • 相关阅读:
    洛谷 P1443 马的遍历
    括号序列 (自出水题)
    19年清北学堂冬令营游记
    计数排列(模板)
    全排列
    unique去重
    链表 模板+详解
    输入输出优化
    关于广/宽度优先搜索
    第四周 6.7-6.13
  • 原文地址:https://www.cnblogs.com/LJB666/p/10817108.html
Copyright © 2011-2022 走看看