zoukankan      html  css  js  c++  java
  • bzoj1026 windy数(数位dp)

    Description
      windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
    在A和B之间,包括A和B,总共有多少个windy数?

    Input
    包含两个整数,A B。

    Output
    一个整数

    Sample Input

    【输入样例一】
    1 10

    【输入样例二】
    25 50

    Sample Output

    【输出样例一】
    9

    【输出样例二】
    20

    【数据规模和约定】
    100%的数据,满足 1 <= A <= B <= 2000000000 。

    分析:数位dp入门题
    首先我们维护一个f[i][j]表示i位数,最高位是j的windy数的数量
    这里写图片描述
    注意一下这里i的循环,我定义的数组是f[N][N],聪明的宝宝一眼就看出循环应该是从2~N-1,然而zz的我把循环写成了2~N,zzz~~~

    之后就是数位dp的经典操作:把数分成若干部分,分部处理
    例:15624
    分成以下部分:
    0~9999
    10000~10999
    11000~11999
    12000~12999
    13000~13999
    14000~14999
    15000~15199
    15200~15299
    15300~15399
    15400~15499
    15500~15599
    15600~15609
    15610~15619
    15620~15624

    在每个部分中累加windy数的个数
    这里写图片描述
    首先把数x用数组存储
    第一个两重循环中要注意,累加的是长度

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    
    using namespace std;
    
    const int N=12;
    int f[N][N]; //f[i][j]表示i位数,最高位是j的windy数的数量
    int A,B,a[15];
    
    int in()
    {
        int t=0;
        char ch=getchar();
        while (ch>'9'||ch<'0') ch=getchar();
        while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-'0',ch=getchar();
        return t;
    }
    
    int abs(int x)
    {
        if (x>=0) return x;
        else return -x;
    }
    
    void cl()
    {
        int i,j,k;
        for (i=0;i<10;i++) f[1][i]=1;
        for (i=2;i<N;i++)  //i<N
            for (j=0;j<10;j++)
                for (k=0;k<10;k++)
                   if (abs(j-k)>=2)
                      f[i][j]+=f[i-1][k];
        return;
    }
    
    int doit(int x)
    {
        if (x==0) return 0;
        int len=0,ans=0;
        while (x) 
        {
            a[++len]=x%10;
            x/=10;
        }
        int i,j,k;
        for (i=1;i<len;i++)
            for (j=1;j<10;j++) ans+=f[i][j];  //j从1开始,最高位不能是0 
        for (i=1;i<a[len];i++)
            ans+=f[len][i];
        for (i=len-1;i>=1;i--)  //i>=1
        {
            for (j=0;j<a[i];j++)  //j<a[i]
                if (abs(a[i+1]-j)>=2) ans+=f[i][j];
            if (abs(a[i+1]-a[i])<2) break;
        }
        return ans;
    }
    
    int main()
    {
        A=in();
        B=in();
        cl();
        printf("%d",doit(B+1)-doit(A));  //
        return 0;
    }
    
  • 相关阅读:
    [HNOI2016]序列
    [Cqoi2015] 编号 【逆向思维,暴力枚举】
    [NOI2015] 软件包管理器【树链剖分+线段树区间覆盖】
    [Hdu-6053] TrickGCD[容斥,前缀和]
    [Hdu-5155] Harry And Magic Box[思维题+容斥,计数Dp]
    牛客NOIP暑期七天营-提高组6
    [SHOI2007] 书柜的尺寸 思维题+Dp+空间优化
    [UVA12235] Help Bubu 思维题+状态定义+Dp
    牛客NOIP暑期七天营-TG3 赛后题解
    牛客NOIP暑期七天营-TG1 赛后题解
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673631.html
Copyright © 2011-2022 走看看