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

    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

    HINT

    【数据规模和约定】

    100%的数据,满足 1 <= A <= B <= 2000000000 。

    正解:数位DP

    解题报告:

      第一道完全弄懂的数位DP题,好好总结一下。

      首先预处理,用f[i][j]表示i位数中最高位为j的windy数的个数,可以很快处理出来。

      我们考虑[a,b]区间完全可以转换为[1,b]-[1,a-1],所以我们先讨论如何统计[1,b]中windy数的个数。

      首先我们对于这个区间内的所有数分一分类,(设b位数为len,并且在ABCDEF这个6位数中,A为第len位,F为第1位,a数组表示每一位数是多少,例如a[len]为最高位数字)

      第一类 达不到len位的所有情况,那么不足的位数补0,所以我们可以直接对于第len-1到第1位放1到9的任何数的f都算一遍所有windy数,加入答案(就是∑f[i][j],1<=i<len,1<=j<=9)

      第二类 达到len位但最高位取不到极限的所有情况,那么我们直接把f[len][i],1<=i<a[len]加入ans即可。

      第三类 达到len为且最高位取极限的所有情况,从len-1到1一路累加答案,枚举到第i位时,默认为i+1到len都取得是极限,也就是说,假如一个数962753,我们已经算完了不足6位和有6位但是最高位小于等于9的所有答案,我们首先令此时最高位为9,然后考虑次高位能够选什么,满足windy数的性质就把其f加入答案。这一步操作相当于默认每一个处理完的位都是取最大值了。要注意一点,当我处理到某位发现当前位与前一位已经不满足windy数了,那么后面无论怎样都不可能满足性质,所以直接break就可以了。 

      

     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 int ans,len;
    21 int a[12];
    22 int f[12][12];//f[i][j]表示i位数中最高位为j的方案数
    23 
    24 inline int getint()
    25 {
    26        int w=0,q=0;
    27        char c=getchar();
    28        while((c<'0' || c>'9') && c!='-') c=getchar();
    29        if (c=='-')  q=1, c=getchar();
    30        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    31        return q ? -w : w;
    32 }
    33 
    34 inline void Init(){
    35     for(int i=0;i<=9;i++) f[1][i]=1;//记得算0
    36     for(int i=2;i<=10;i++) 
    37     for(int j=0;j<=9;j++)
    38         for(int k=0;k<=9;k++)
    39         if(abs(j-k)>=2) f[i][j]+=f[i-1][k];    
    40 }
    41 
    42 inline int solve(int x){
    43     if(x<=0) return 0;
    44     ans=0; len=0; while(x) { a[++len]=x%10; x/=10; }
    45     //part 1 达不到len位的所有情况
    46     for(int i=len-1;i;i--) for(int j=1;j<=9;j++) ans+=f[i][j];//前面位数全部取0,即高位没有数
    47     //part 2 达到len位但最高位取不到极限的所有情况
    48     for(int i=1;i<a[len];i++) ans+=f[len][i];//计算最高位达不到极限的所有情况,显然都可行
    49     //part 3 达到len为且最高位取极限的所有情况,从len-1到1一路累加答案,枚举到第i位时,默认为i+1到len都取得是极限
    50     for(int i=len-1;i;i--) {//计算每一位取极限的值,一路往下累加答案
    51     for(int j=0;j<a[i];j++) if(abs(a[i+1]-j)>=2) ans+=f[i][j];//似乎可以取0
    52     if(abs(a[i+1]-a[i])<2) break;//高位都取极限已经不满足windy数性质,直接break
    53     }
    54     return ans;
    55 }
    56 
    57 inline void work(){
    58     int sx=getint(),sy=getint();
    59     Init();
    60     printf("%d",solve(sy+1)-solve(sx));
    61 }
    62 
    63 int main()
    64 {
    65   work();
    66   return 0;
    67 }
  • 相关阅读:
    利用windows 127.0.0.1:30000 代理在linux下工作
    nginx与ssh 把内网转为公网开发服务器
    php errorlog 记录
    dockerfile php 开发
    ubuntu
    k8s 1.9.1 centos7 install 离线安装
    kubernetes
    linux字符设备驱动--基本知识介绍
    linux应用程序设计--Makefile工程管理
    linux应用程序设计--GDB调试
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5768503.html
Copyright © 2011-2022 走看看