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\n",ans1-ans2);
57     return 0;
58 }

 

posted @ 2017-12-28 20:39  CHerish_OI  阅读(...)  评论(... 编辑 收藏