码迷,mamicode.com
首页 > Windows程序 > 详细

bzoj 1026 SCOI2009 windy数

时间:2016-07-20 22:52:13      阅读:298      评论:0      收藏:0      [点我收藏+]

标签:

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题,心里好开心>_<

  因为网上我找不到什么好的题解,所以我觉得最好我自己再写一篇虽然也不一定写得好

  首先,我们可以预处理出在没有任何限制的情况下的windy数。令dp[i][j]表示第i位填j的方案数,我从后往前写的转移,显然dp[i][j]等于sigma(dp[i+1][k])(abs(k-j)>=2)。

  接下来,我们可以处理出f[i]表示在第i位取该位最大值的方案数。设这个数第i位为a[i],则转移为f[i]=sigma(dp[i+1][k])(k<=a[i+1] && abs(a[i]-k)>=2)

  然后,我们可以考虑如何统计答案。既然要求[l,r]之间的windy数个数,那么显然可以转为前缀和的差。设solve(i)为小于等于i的windy数个数,则ans=solve(r)-solve(l-1)

  那么,我们只需知道小于等于x的windy数个数即可。我们来考虑下。

  首先,我们可以先找到这个数第一个不为0的地位置w。然后,这个位置显然可以放1~a[w]-1,这部分的答案为sigma(dp[w][i])(1<=i<a[w])。然后,当这个位置放a[w]的方案数为f[w]

  但接下来我们还要处理掉前导0的情况。我们可以发现,只有前导0超过w个的数才需要统计。于是,我们再统计一下sigma(dp[i][j])(i>w && 1<=j<=9)。然后就是输出了

  下面是代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 7 #define INF 2147483647
 8 
 9 using namespace std;
10 typedef long long llg;
11 
12 int a[2][20],g[20][10],n,ans,x,y,z;
13 int f[20];
14 
15 void init(int x){
16     int now=0,ww=1;
17     while(!a[x][ww] && ww<=n) ww++;
18     memset(g,0,sizeof(g));
19     memset(f,0,sizeof(f)); f[n]=1;
20     for(int i=0;i<=9;i++) g[n][i]=1;
21     for(int i=n-1;i;i--){
22         for(int j=0;j<=9;j++)
23             for(int k=0;k<=9;k++)
24                 if(abs(j-k)>=2) g[i][j]+=g[i+1][k];
25         for(int j=0;j<a[x][i+1];j++)
26             if(abs(a[x][i]-j)>=2) f[i]+=g[i+1][j];
27         if(abs(a[x][i]-a[x][i+1])>=2) f[i]+=f[i+1];
28     }
29     for(int i=ww+1;i<=n;i++)
30         for(int j=1;j<=9;j++) now+=g[i][j];
31     if(ww<=n){
32         for(int i=1;i<a[x][ww];i++) now+=g[ww][i];
33         now+=f[ww];
34     }
35     if(x) ans+=now; else ans-=now;
36 }
37 
38 int main(){
39     File("a");
40     scanf("%d %d",&x,&y);
41     x--;z=y; while(z) n++,z/=10;
42     for(int i=n;i;i--){
43         a[0][i]=x%10,x/=10;
44         a[1][i]=y%10,y/=10;
45     }
46     init(0); init(1);
47     printf("%d",ans);
48     return 0;
49 }

bzoj 1026 SCOI2009 windy数

标签:

原文地址:http://www.cnblogs.com/lcf-2000/p/5689755.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!