zoukankan      html  css  js  c++  java
  • 蒟蒻的数位DP专题总结

    BZOJ  1026: [SCOI2009]windy数:

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1026

              dp[11][11][2]:dep,pre,f

               要求的性质就是相邻数字差至少是2。
              递归函数的状态设计如下dep,pre,f,分别表示已经枚举到第dep位,他的前一位(更高的位)是pre,f表示大小关系是否已经确定.

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=500000+50;
    #define mod 1000000007
    #define inf 10000007
    
    int dp[11][11][2],vis[11][11][2],d[11];
    int dfs(int dep,int pre,int f) {
        if(dep<0) return 1;
        else if(pre>=0&&vis[dep][pre][f]) return dp[dep][pre][f];
        else {
            int re=0;
            if(pre == -1) {
                re+=dfs(dep-1,-1,f||d[dep]>0);
                if(f) for(int i=1;i<=9;i++) re+=dfs(dep-1,i,1);
                else {
                    for(int i=1;i<=d[dep];i++) {
                        re+=dfs(dep-1,i,i<d[dep]);
                    }
                }
            }
            else  {
                if(f) {
                    for(int i=0;i<10;i++) {
                        if(abs(i-pre)>1) {
                            re+=dfs(dep-1,i,1);
                        }
                    }
                }
                else {
                    for(int i=0;i<10;i++) {
                        if(i<=d[dep]&&abs(i-pre)>1) {
                            re+=dfs(dep-1,i,i<d[dep]);
                        }
                    }
                }
            }
            if(pre>=0) vis[dep][pre][f]=1,dp[dep][pre][f]=re;
            return re;
        }
    }
    int cal(int n) {
       mem(dp);mem(vis);
       int len=0;
       while(n) {
        d[len++]=n%10;n/=10;
       }
       return dfs(len-1,-1,0);
    }
    int main() {
        int a,b;
        while(scanf("%d%d",&a,&b)!=EOF) {
            cout<<cal(b)-cal(a-1)<<endl;
        }
       return 0;
    }
    BZOJ1026

     BZOJ 3209: 花神的数论题:

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3209

                 求的是1到N内进制种类数的个数的乘积,显然是数学题嘛。。。。

                 仔细想想:我们如果只考虑二进制上01的个数,也就是如果枚举1的个数,将二进制上含有i个1的个数用数位dp求解出来,再算快速幂,就可以得到答案了

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=60+50;
    #define mod 10000007
    #define inf 10000007
    #define maxn 10000
    
    ll dp[65][65][3],vis[65][65][3],d[N],c[N][N],ans[N];;
    ll dfs(int dep,int left,int f) {
       if(vis[dep][left][f]) return dp[dep][left][f];
       if(dep+1<left) return 0;if(left==0) return 1;
       ll& re=dp[dep][left][f];
       vis[dep][left][f]=1;
       if(!f) {
           if(d[dep]==0) {
            re+=dfs(dep-1,left,f);
           }
           else {
            re+=dfs(dep-1,left,1);
            re+=dfs(dep-1,left-1,0);
           }
       }
       else {
         re+=c[dep+1][left];
       }//vis[dep][left][f]=1,dp[dep][left][f]=re;
       return re;
    }
    ll quick_pow(ll n,ll m) {
       ll ret=1;
       while(m) {
         if(m&1) ret=(ret*n)%mod;
         n=(n*n)%mod;
         m>>=1;
       }
       return ret;
    }
    ll cal(ll n) {
        int len=0;mem(vis);mem(dp);
        while(n) {
            d[len++]=n%2;
            n/=2;
        }
        for (int i=1;i<=len;i++) {
            ans[i]=dfs(len-1,i,0);
        }
        ll A=1;
        for(int i=2;i<=len;i++)A=(A*quick_pow(i,ans[i]))%mod;
        return A;
    }
    int main(){
           ll n;
           for(int i=0;i<=60;i++) {
            c[i][0]=c[i][i]=1;
            for(int j=1;j<i;j++) {
                c[i][j]=c[i-1][j]+c[i-1][j-1];
            }
           }
           while(scanf("%lld",&n)!=EOF) {
            printf("%lld
    ",cal(n));
           }
      return 0;
    }
    BZOJ3209

    BZOJ 1799: [Ahoi2009]self 同类分布:

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1799

                  因为最多18位,最大也就是18*9,我们枚举位数和,去数位dp就可以了

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=600+50;
    #define mod 10000007
    #define inf 10000007
    #define maxn 10000
    
    ll dp[20][200][200][2],vis[20][200][200][2];
    int d[N];
    ll dfs(int dep,int T,int f,int sum,int M) {
       if(dep<0) return T == 0 && sum == M;
       if(sum>M)return 0;
       if(vis[dep][T][sum][f]) return dp[dep][T][sum][f];
       ll& re=dp[dep][T][sum][f];
       vis[dep][T][sum][f]=1;
       if(f) {
         for(int i=0;i<=9;i++) {
            re+=dfs(dep-1,(T*10+i)%M,f,sum+i,M);
         }
       }
       else {
        for(int i=0;i<=d[dep];i++) {
            re+=dfs(dep-1,(T*10+i)%M,i<d[dep],sum+i,M);
        }
       }
       return re;
    }
    
    ll cal(ll x) {
       int len=0;
       ll A=0;
       while(x) d[len++]=x%10,x/=10;
       for(int i=1;i<=9*len;i++) {
            mem(dp),mem(vis);
            A+=dfs(len-1,0,0,0,i);
       }
        return A;
    }
    int main() {
        ll l,r;
        while(scanf("%I64d%I64d",&l,&r)!=EOF) {
            printf("%I64d
    ",cal(r)-cal(l-1));
            //cout<<cal(r)-cal(l-1)<<endl;
        }
        return 0;
    }
    BZOJ1799

     HDU 4734 F(x):

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734

                  我们先求出F(A),题意只要求满足F(x)<=F(A) 的就行,所以我们从构造数位dp  将F(A)设为上限,

                  F(A)可以发现最大就是9*2^9多一点,我们再枚举一个数位大小的时候,将剩余上限减去使用当前数位的F()贡献

                  最后也就是枚举完,剩余>=0就可行

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=6000+50;
    #define mod 10000007
    #define inf 10000007
    #define maxn 10000
    
    int dp[10][N],vis[10][N],d[20];
    
    int dfs(int dep,int sum,int f) {
        if(sum<0) return 0;
        if(dep<0) return sum>=0;
        if(f&&vis[dep][sum]) return dp[dep][sum];
        if(f) {
            int& re=dp[dep][sum];
            vis[dep][sum]=1;
            for(int i=0;i<=9;i++) {
                re+=dfs(dep-1,sum-i*(1<<dep),f);
            }
            return re;
        }
        else {
            int re=0;
            for(int i=0;i<=d[dep];i++) {
                re+=dfs(dep-1,sum-i*(1<<dep),i!=d[dep]);
            }
            return re;
        }
    }
    int cal(int A,int B) {
        if(B==0) return 1;
        int sum=0;int len=0;//mem(dp),mem(vis);
        while(A) sum+=(A%10)*(1<<len),len++,A/=10;
        len=0;
        while(B) d[len++]=B%10,B/=10;
        return dfs(len-1,sum,0);
    }
    
    int main() {
        int T=read();
        int A,B;
        for(int i=1;i<=T;i++) {
           A=read(),B=read();
            printf("Case #%d: ",i);
            printf("%d
    ",cal(A,B));
        }
        return 0;
    }
    HDU4734

     HDU 3555 Bomb:

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555

                 求1到N内有49相连的数字个数,经典数位;

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=6000+50;
    #define mod 10000007
    #define inf 10000007
    #define maxn 10000
    
    ll dp[60][60],vis[50][60],d[60];
    ll dfs(int dep,int pre,int f) {
        if(dep<0) return 1;
        if(f&&vis[dep][pre]) return dp[dep][pre];
        if(f) {
                ll& re=dp[dep][pre];
               vis[dep][pre]=1;
            for(int i=0;i<=9;i++) {
                if(pre!=4||(pre==4&&i!=9)) {
                    re+=dfs(dep-1,i,f);
                }
            }return re;
        }
        else {
            ll re=0;
            for(int i=0;i<=d[dep];i++) {
                if(pre!=4||(pre==4&&i!=9)) 
                re+=dfs(dep-1,i,i<d[dep]);
            } return re;
        }
    }
    ll cal(ll x) {
        int len=0;mem(dp),mem(vis);
        while(x) d[len++]=x%10,x/=10;
        return dfs(len-1,0,0);
    }
    int main() {
    
        int T=read();
        while(T--) {
            ll n;
            scanf("%I64d",&n);
            cout<<n-cal(n)+1<<endl;
        }
        return 0;
    }
    HDU3555

     HDU 3709 Balanced Number:

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3709

                 我们枚举平衡点就OK,注意0 的次数重复计算了,减去len-1就是答案

    ///1085422276
    
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    using namespace std ;
    typedef long long ll;
    #define mem(a) memset(a,0,sizeof(a))
    #define pb push_back
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')f=-1;ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;
    }
    //****************************************
    const int  N=6000+50;
    #define mod 10000007
    #define inf 10000007
    #define maxn 10000
    
    ll dp[20][6000][20],vis[20][6000][20],d[N];
    ll dfs(int dep,int D,int mid,int f) {
       if(dep<0) return D==3000;
       if(f&&vis[dep][D][mid]) return dp[dep][D][mid];
       if(f) {
         vis[dep][D][mid]=1;
         ll& re=dp[dep][D][mid];
         for(int i=0;i<=9;i++) {
            re+=dfs(dep-1,D-(dep-mid)*i,mid,f);
         }
         return re;
       }
       else {
        ll re=0;
        for(int i=0;i<=d[dep];i++) {
            re+=dfs(dep-1,D-(dep-mid)*i,mid,i<d[dep]);
        }
        return re;
       }
    
    }
    ll cal(ll x) {
       if(x==0) return 1;
       if(x<0) return 0;
       int len=0;ll re=0;mem(dp),mem(vis);
       while(x) d[len++]=x%10,x/=10;
       for(int i=0;i<len;i++) {
         re+=dfs(len-1,3000,i,0);
       }
       return re-len+1;
    }
    int main() {
    
        int T=read();
        while(T--) {
                ll l,r;
          scanf("%I64d%I64d",&l,&r);
          cout<<cal(r)-cal(l-1)<<endl;
        }
        return 0;
    }
    HDU3709
  • 相关阅读:
    redis安装
    查看数据库
    redis启动出错Creating Server TCP listening socket 127.0.0.1:6379: bind: No error
    java 面向对象基础
    SpringBoot简单公共返回类
    swift闭包_002_swift闭包
    swift的函数类型_001_swift函数类型基本使用
    swift函数_11_函数的嵌套使用
    swift函数_10_swift中函数基本使用
    swift可选类型_09_optional基本使用
  • 原文地址:https://www.cnblogs.com/zxhl/p/4954444.html
Copyright © 2011-2022 走看看