windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
包含两个整数,A B。
一个整数
【数据规模和约定】
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 }
原文:http://www.cnblogs.com/lcf-2000/p/5689755.html