• bzoj1026: [SCOI2009]windy数(传说你是数位DP)


    1026: [SCOI2009]windy数

    题目:传送门 

    题解:

       其实之前年少无知的时候好像A过...表示当时并不知道什么数位DP

       今天回来深造一发...

       其实如果对这个算法稍有了解...看到这题的数据范围应该就YY出来了(蒟蒻博主表示很无力)

       好吧讲做法:

       这题的DP其实只是在于一开始的预处理:定义f[i][j]表示长度为i且最高位为j的windy数

       那么转移方程再YY一发:

      1 for(int i=0;i<=9;i++)f[1][i]=1;
      2     for(int i=2;i<=10;i++)
      3         for(int j=0;j<=9;j++)
      4             for(int k=0;k<=9;k++)
      5                 if(abs(j-k)>=2)
      6                     f[i][j]+=f[i-1][k];

       之后就是怎么利用这个f数组了,一个常规套路:

       对于区间[a,b]的答案,如果我们可以求出1~b的答案和1~a-1的答案,那么输出[1~b]-[1~a-1]就是答案了啊。。

       那么我的做法是用一个getsum函数,求出1~n-1的答案,最后两个区间相减就ok

       具体看代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define qread(x) x=read()
     7 using namespace std;
     8 inline int read()
     9 {
    10     int f=1,x=0;char ch;
    11     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    13     return f*x;
    14 }
    15 int A,B;
    16 int f[11][11];//长度为i,最高位为j
    17 int w[11];
    18 int getsum(int n)//求区间1~n-1的答案 
    19 {
    20     int len=0,ans=0;
    21     memset(w,0,sizeof(w));
    22     while(n!=0)
    23     {
    24         w[++len]=n%10;
    25         n/=10;
    26     }
    27     for(int i=1;i<len;i++)//比自己至少小一位 
    28         for(int j=1;j<=9;j++)//枚举开头(所以不能为‘0’) 
    29             ans+=f[i][j];
    30     for(int i=1;i<w[len];i++)//和自己同样位数,但是最高位比自己小 
    31         ans+=f[len][i];
    32     for(int i=len-1;i>=1;i--)//最高位一样 
    33     {
    34         for(int j=0;j<w[i];j++)
    35         {
    36             if(abs(j-w[i+1])>=2)
    37                 ans+=f[i][j];
    38         }
    39         if(abs(w[i+1]-w[i])<2)
    40             break;
    41     }
    42     return ans;
    43 }
    44 int main()
    45 {
    46        qread(A);qread(B);if(A>B)swap(A,B);
    47     for(int i=0;i<=9;i++)f[1][i]=1;
    48     for(int i=2;i<=10;i++)
    49         for(int j=0;j<=9;j++)
    50             for(int k=0;k<=9;k++)
    51                 if(abs(j-k)>=2)
    52                     f[i][j]+=f[i-1][k];
    53     int ans1=getsum(B+1);
    54     int ans2=getsum(A);
    55     //因为getsum求的是1~n-1这个区间的答案,所以我们输出getsum(B+1)-getsum(A);
    56     printf("%d
    ",ans1-ans2);
    57     return 0;
    58 }
  • 相关阅读:
    CI登录验证
    兼容所有浏览器的JS动态显示当前日期时间
    Active Record 数据库模式-增删改查操作
    数据库链接的增操作举例
    CI框架获取post和get参数 CodeIgniter
    PHP日期操作类代码-农历-阳历转换、闰年、计算天数等
    根据两点间的经纬度计算距离
    Session 类
    mysql 查询优化规则
    php获取文件夹下面的文件列表和文件夹列表
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8137664.html
Copyright © 2020-2023  润新知