windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
标签:
http://www.lydsy.com/JudgeOnline/problem.php?id=1026
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
我们用\(dp[i][j]\)表示以\(j\)开头的\(i\)为数中windy数一共有多少.
然后用\(solve(x)\)求出\([1,x]\)内的windy数一共有多少,步骤如下:
1.将\(x\)一位一位拆开,共\(cnt\)位,第\(i\)位为\(num[i]\).
2.统计以\(1,2,3,...,9\)开头的\(i\)位数中共有多少windy数,其中\(i<cnt\).
3.对于\(cnt\)位数,显然我们是不能把\(dp[cnt][num[cnt]\)加进去的.比如\(x=5786\),以\(5\)开头的\(4\)位数没有完全包含,所以只能从\(dp[cnt][1]\)计算到\(dp[cnt][num[cnt]-1]\),然后对于第\(cnt\)位为\(num[cnt]\)的,就到\(cnt-1\)位去计算.(相当于数钱,一共5786,数到4999,不能直接数5999,对于>=5000的,要从百位开始数了).
4.依次往后退,但是注意,当\(num[i]\)与\(num[i+1]\)相差不到\(2\)的话,对于第\(i\)位是\(num[i]\)的情况就不需要考虑了,也就不用继续下去了.
5.由于第\(cnt\)位不能取\(0\),而只有最后一位可以去\(num[i]\),比较特殊,所以需要单独处理,可以特判一位数的情况,确保至少有最高位和最低位两个不同的位.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 int num[11]; 6 ll dp[11][11]; 7 ll a,b; 8 inline ll read(ll &x){ x=0;ll k=-1;char c;for(c=getchar();c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)k=-1;for(;c>=‘0‘&&c<=‘9‘;c=getchar())x=x*10+c-‘0‘;return x*k; } 9 ll solve(int x){ 10 if(x<10) return x; 11 ll ans=0; int cnt=0; 12 while(x) num[++cnt]=x%10, x/=10; 13 for(int i=1;i<cnt;i++) ans+=dp[i][10]-dp[i][0]; 14 for(int i=1;i<num[cnt];i++) ans+=dp[cnt][i]; 15 for(int i=cnt-1;i;i--){ 16 for(int j=0;j<num[i];j++)if(abs(num[i+1]-j)>1) 17 ans+=dp[i][j]; 18 if(i==1&&abs(num[i+1]-num[i])>1) ans++; 19 if(abs(num[i+1]-num[i])<=1) break; 20 } 21 return ans; 22 } 23 int main(){ 24 read(a); read(b); 25 for(int i=0;i<10;i++) dp[1][i]=1; 26 dp[1][10]=10; 27 for(int i=2;i<=10;i++)for(int j=0;j<10;j++){ 28 for(int k=0;k<10;k++)if(abs(j-k)>1) 29 dp[i][j]+=dp[i-1][k]; 30 dp[i][10]+=dp[i][j]; 31 } 32 printf("%lld\n",solve(b)-solve(a-1)); 33 }
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
包含两个整数,A B。
一个整数
【数据规模和约定】
100%的数据,满足 1 <= A <= B <= 2000000000 。
BZOJ_1026_[SCOI2009]_windy数_(数位dp)
标签:
原文地址:http://www.cnblogs.com/Sunnie69/p/5598873.html