BZOJ 1026 [SCOI2009] windy数
2017-03-17 08:35
423 查看
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 。
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~数位DP~
用f[i][j]表示第i位上填j时的方案数,那么f[i][j]=sum{f[i-1][k]},其中abs(j,k)>=2。
要得到[a,b]的答案,我们可以用ans[1,b]-ans[1,a-1],所以要计算的就是[1,u]的答案。
我们可以把它分为两个部分(设数u的第i位为x[i],总位数为tot):
(1)计算首位不为x[tot]的种类数,枚举位数,首位贡献的答案是f[tot][1...x[tot]-1],其余每位贡献的答案是f[i][1...9];
(2)计算首位为x[tot]的种类数,从高往低枚举,先计算完第i位<x[i]的种类数,再以第i位是x[i]为基准往下计算。这里注意,如果abs(x[i],x[i+1])<2,就不用再往下计算。
但是用上面的方法计算出来的是1~u-1的种类数,所以我们在输出的时候要输出ans[1,u-1]。
答案一定小于2*10^9,int就够了。
#include<cstdio> int a,b,f[12][10]; int abs(int u) { return u>0 ? u:-u; } int cal(int u) { if(!u) return 0; int x[12],tot=0,ans=0; while(u) x[++tot]=u%10,u/=10; for(int i=1;i<x[tot];i++) ans+=f[tot][i]; for(int i=tot-1;i;i--) for(int j=1;j<=9;j++) ans+=f[i][j]; for(int i=tot-1;i;i--) { for(int j=0;j<x[i];j++) if(abs(x[i+1]-j)>=2) ans+=f[i][j]; if(abs(x[i+1]-x[i])<2) break; } return ans; } int main() { scanf("%d%d",&a,&b); for(int i=0;i<=9;i++) f[1][i]=1; for(int i=1;i<=11;i++) for(int j=0;j<=9;j++) for(int k=0;k<=9;k++) if(k>j+1 || j>k+1) f[i][j]+=f[i-1][k]; printf("%d\n",cal(b+1)-cal(a)); return 0; }
相关文章推荐
- 【BZOJ 1026】 [SCOI2009]windy数
- 数位DP BZOJ 1026 [SCOI2009]windy数
- [BZOJ1026][SCOI2009]windy数 解题报告|数位dp
- [BZOJ1026][SCOI2009]windy数
- bzoj 1026: [SCOI2009]windy数(数位dp)
- bzoj 1026: [SCOI2009]windy数 数位dp
- bzoj1026 [SCOI2009]windy数
- BZOJ 1026 [SCOI2009]windy数
- bzoj1026 [SCOI2009]windy数
- bzoj 1026: [SCOI2009]windy数 数位dp
- bzoj1026 [SCOI2009]windy数 数位DP
- 【bzoj1026】[SCOI2009]windy数 数位DP
- BZOJ 1026([SCOI2009]windy数-数位DPlevel up)
- BZOJ1026(SCOI2009)[windy数]--数位DP
- [bzoj]1026: [SCOI2009]windy数
- BZOJ1026:[SCOI2009]windy数——题解
- [BZOJ1026][SCOI2009]windy数
- bzoj 1026: [SCOI2009]windy数 & 数位DP算法笔记
- [bzoj1026][SCOI2009]windy数
- [BZOJ1026][SCOI2009]windy数(数位DP)