uestc 250 windy数(数位dp)

来源:互联网 发布:java得到项目路径 编辑:程序博客网 时间:2024/05/16 19:13


题目链接

windy数

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

windy定义了一种windy数。

不含前导零且相邻两个数字之差至少为22的正整数被称为windy数。

windy想知道,在AABB之间,包括AABB,总共有多少个windy数?

Input

包含两个整数,AA BB

满足 1AB20000000001≤A≤B≤2000000000 .

Output

Sample input and output

Sample InputSample Output
1 10
9

Source

Windy



题解:

数位dp,可以按平常老套路写,不过这一题比较特殊,可以预先处理出以i开头的长度为len的windy数(不管有无前导0),然后累加上去,详见代码。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>using namespace std;typedef long long ll;ll d[11][15];int a[15];int abs(int x);void init(){for(int i=0;i<10;i++) d[1][i]=1;for(int i=2;i<=15;i++){for(int j=0;j<10;j++){for(int k=0;k<10;k++){if(abs(j-k)>=2)d[i][j]+=d[i-1][k];}}}}ll cal(ll x){if(x==0) return 0;int len=0;while(x){a[++len]=x%10;x/=10;}ll ans=0;for(int i=1;i<len;i++) for(int j=1;j<10;j++)  ans+=d[i][j];for(int i=1;i<a[len];i++)ans+=d[len][i];bool flag=true;for(int i=len-1;i>=1;i--){for(int j=0;j<a[i];j++) if(abs(a[i+1]-j)>=2) ans+=d[i][j];if(abs(a[i+1]-a[i])<2){flag=false;break;}}if(flag) ans++;return ans;}int main(){init();ll a,b;while(~scanf("%lld%lld",&a,&b)){ll ans=cal(b)-cal(a-1);printf("%lld\n",ans);}return 0;}

老套路写法:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>using namespace std;typedef long long ll;ll d[15][12];int a[15];ll dfs(int pos,int pre,int st,int flag)  //st为0表示前面几位都是0,flag为0表示达到上限 {ll ans=0;if(pos==0) return st==1;if(st&&flag){if(~d[pos][pre]) return d[pos][pre];}int e=flag? 9:a[pos];for(int u=0;u<=e;u++){if(abs(u-pre)>=2||!st)ans+=dfs(pos-1,u,st||u>0,flag||u<e);}if(st&&flag) d[pos][pre]=ans;return ans;}ll cal(ll x){if(x==0) return 0;int len=0;while(x){a[++len]=x%10;x/=10;}return dfs(len,11,0,0);}int main(){memset(d,-1,sizeof(d));ll a,b;while(~scanf("%lld%lld",&a,&b)){printf("%lld\n",cal(b)-cal(a-1));}return 0;}


































0 0
原创粉丝点击