zoukankan      html  css  js  c++  java
  • P2657 [SCOI2009]windy数

    P2657 [SCOI2009]windy数

    题解

    数位DP板子题

    Solution 1

    f[ i ][ j ] 表示长度为 i 的数字,最高温填的数字是  j  的时候,windy数的个数

    f[ i ][ j ] = Σ f[ i ][ k ] ( abs(k-j)>=2 )

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int aa,bb;
    int f[11][10];
    //f[i][j] 从后往前数第i位填了数字j的windy数个数
    //或者可以理解为长度为i的数字,最高位填了数字j的windy数个数 
    
    void pre()   //预处理 
    {
        for(int i=0;i<=9;i++) f[1][i]=1;
        //单数位的数字也是windy数 
        
        for(int i=2;i<=10;i++)
          for(int j=0;j<=9;j++)
             for(int k=0;k<=9;k++)
               if(abs(j-k)>=2)
                  f[i][j]+=f[i-1][k];
    }
    
    int work(int x)  //1~x-1中有多少个windy数 
    {
        int ans=0;
        int a[11],len=0;
        while(x)  //存下x的各位数字 
        {
            a[++len]=x%10;
            x/=10;
        }
        
        for(int i=1;i<len;i++)
          for(int j=1;j<=9;j++)
            ans+=f[i][j];
        //长度比x小的数字一定是合法的 
        
        for(int i=1;i<=a[len]-1;i++)
            ans+=f[len][i];  
        //最高位数字比x最高位小的也一定合法 
        
        for(int i=len-1;i>=1;i--)  //从高位向低位枚举 
        {
            for(int j=0;j<=a[i]-1;j++) //x是上界,不可以超过x ,j是第i位上的数字 
               if(abs(j-a[i+1])>=2) ans+=f[i][j]; //和上一位比较,合法 
            if(abs(a[i+1]-a[i])<2) break; //上一位和自己比较,不合法,直接退出for循环 
        }
        
        return ans;  
    }
    
    int main()
    {
        aa=read();bb=read();
        pre();
        printf("%d",work(bb+1)-work(aa));
        return 0;
    }

    Solution 2

    dfs记忆化搜索实现  (实际是套路)

    dp[ i ][ j ]表示填到 第 i 位 ,上一位填的数字是 j 的方案数,初始化 -1 ,表示都没有计算过

    记 sum(  i  ) 表示 i 以内的windy数个数,ans=sum( b ) - sum( a-1 ) 

    我们拿到一个数首先把它一位一位拆开放到数组里

    填数字的时候考虑从最高位填到最低位(从低到高也行)

    下面DFS记忆化搜索

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int a,b,dp[15][15];
    int c[15],len;
    
    int dfs(int pos,int pre,bool qdl,bool limit)
    //填到(该填)第pos位了,上一位填的数字是pre,qdl判断是否前面全是0,limit判断是否顶上界 
    {
        if(pos<=0) return 1;  //已经填完了 
        if(!limit&&dp[pos][pre]!=-1) return dp[pos][pre];  //已经算过了,而且不顶上界合法 
        int res=0;
        int up=limit?c[pos]:9; //当前位置的上界(最大可以填到多少) 
        for(int i=0;i<=up;i++)
            if(!qdl&&abs(i-pre)>=2||qdl) 
            //1.所填的位置前面全是0,可以继续 
            //2.前面不是全位0,并且符合windy数(abs>=2),可以继续 
               res+=dfs(pos-1,i,qdl&&i==0,limit&&i==up);
               //位置后移,记录新pre,判断是否全为0,是否顶上界 
        if(!limit&&!qdl) dp[pos][pre]=res; //不顶上界不是全部前导零就记录答案 
        return res;
    }
    
    int sum(int x)
    {
        memset(c,0,sizeof(c));
        len=0;
        memset(dp,-1,sizeof(dp));
        while(x)
        {
            c[++len]=x%10;
            x/=10;
        }
        return dfs(len,0,1,1);
    }
    
    int main()
    {
        a=read();b=read();
        printf("%d
    ",sum(b)-sum(a-1));
        return 0;
    }
  • 相关阅读:
    android studio遇到的一系列问题
    flask接口入门实现简单的登录注册(二)
    flask接口入门实现简单的登录注册(一)
    第一节:django环境 模型 视图 后台
    设计模式二:建造者模式
    设计模式一:工厂模式
    mysql系列:创建数据库和用户及赋权
    mysql系列:mysql的数据类型
    mysql系列:数据库范式与mysql引擎
    mysql系列:centos7.6上安装mysql8.0
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11318142.html
Copyright © 2011-2022 走看看