zoukankan      html  css  js  c++  java
  • 数位dp

    数位dp大致解决的是一类数字问题:从l到r有多少个数符合某个性质

    设立前缀的状态时,一般有前缀的状态为:上一位的值,前缀的数字和,前缀所有数字的gcd,该前缀取模某个数的余数等等

    例题:洛谷 P2657

    f[i][j]表示数字位数为i,前缀的状态为j的windy数数量

    递归版

    #include <bits/stdc++.h>
    #define debug frelimiten("r.txt","r",stdin)
    #define mp make_pair
    #define ri register int
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int maxn = 1e3+5;
    const int INF = 0x3f3f3f3f; 
    const int mod = 998244353;
    inline ll read(){ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
    int f[maxn][maxn],digit[maxn],T;
    ll n,m;
    //f数组表示当前将要考虑的是从高到低的第i位(这个位要取0~9任意无限制的数),当前该前缀的状态为st时的数字个数 
    int dfs(int x,int st,bool limit) //x:第x位(从高位到低位) st:上一位数字(11则表示为前导0)  limit:上一位是否达到上限
    {
        if (x==0) return 1;
        if (!limit && f[x][st]!=-1) return f[x][st];
        int up=(limit?digit[x]:9);
        int ans=0;
        for (ri i=0;i<=up;i++)
          {
            if (abs(st-i)<2) continue;
            if (st==11 && i==0)
                ans+=dfs(x-1,11,limit&&(i==up));
            else
                  ans+=dfs(x-1,i,limit&&(i==up));
          }
          if (!limit) f[x][st]=ans;
          return ans;
    }
    int solve(int x) 
    {
        memset(f,-1,sizeof(f));
        int len=0;
        for(;x;x/=10)
        {
            digit[++len]=x%10;
        }
        return dfs(len,11,true);   
    }
    int main()
    {
        T=1;
        while (T--)
        {
            n=read(),m=read();
            cout<<solve(m)-solve(n-1)<<endl;       
        }
        return 0;
    }
    View Code

    非递归版

    #include <bits/stdc++.h>
    #define debug frelimiten("r.txt","r",stdin)
    #define mp make_pair
    #define ri register int
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int maxn = 5e3+5;
    const int INF = 0x3f3f3f3f; 
    const int mod = 998244353;
    const int N=10005,M=4000005;
    inline ll read(){ll s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;}
    ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
    int p,q,dp[15][15],digit[15];
    void init()
    {
        for (ri i=0;i<=9;i++) dp[1][i]=1;
        for (ri i=2;i<=10;i++) 
            for (ri j=0;j<=9;j++)
                for (ri k=0;k<=9;k++)
                    if (abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
    }
    int solve(int x)
    {
        memset(digit,0,sizeof(digit));
        int len=0,ans=0;
        while (x)
        {
            digit[++len]=x%10;
            x/=10;
        }
        /*
            000x
            00xx
            0xxx...
        */
        //求len-1位的windy数 必定包含在区间里的 
        for (ri i=1;i<len;i++)
            for (ri j=1;j<=9;j++)
                ans+=dp[i][j];
        /*
            1xxx
            2xxx
            3xxx
            .
            .
            (a-1)xxxx
        */
        //然后是len位 但最高位<digit[len]的windy数 也包含在区间里 
        for (ri i=1;i<digit[len];i++)
            ans+=dp[len][i];
        /*
        a [0,b)[0,c)[0,d)...
        */
        for (ri i=len-1;i;i--)
        {
            for (ri j=0;j<digit[i];j++)
                if (abs(j-digit[i+1])>=2) ans+=dp[i][j];
            if (abs(digit[i+1]-digit[i])<2) break;
            if(i==1) ans+=1;
        }
        return ans;
    }
    int main()
    {
        init();
        cin>>p>>q;
        cout<<solve(q)-solve(p-1)<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    js中字符串的操作
    javascript中null与undefined的区别
    javascript中=、==与===的区别
    less
    火狐浏览器下点击a标签时出现虚线的解决方案
    js删除数组中重复的元素
    js中的indexOf
    css选择器
    bootstrap-table组合表头
    使用yo -v查看yeoman版本号
  • 原文地址:https://www.cnblogs.com/Y-Knightqin/p/12846937.html
Copyright © 2011-2022 走看看