1026: [SCOI2009]windy數
阿新 • • 發佈:2018-07-03
online www. scan pan names def status str mit Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 9670 Solved: 4445
[Submit][Status][Discuss]
1 10
【輸入樣例二】
25 50Sample Output
【輸出樣例一】
9
【輸出樣例二】
20
Submit: 9670 Solved: 4445
[Submit][Status][Discuss]
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 。
windy數的大致意思是:像135,6913,13579,這樣每兩個相鄰數字的差≥2
數位dp:
正面直接猜想,保存2000000000狀態無疑是不可能的,必須采用更加巧妙的方法。
可以設dp數組為:f[i][j],i表示數字位數,j表示最高位的數字
因此可以得到dp方程:
\[f[i][j]=\sum_{k=0}^{k\leq 9} f[i-1][k]\left (\left | k-j \right |\geq 2\right )\]
但這只計算出最高位為j的結果,無法求出範圍內的結果,這時可以轉換思想,求出1~b的結果減去1~a-1的結果,不就是答案了嗎?
設len表示數字位數,T[i]表示第i位的數字
首先,ans加上1~len-1位的情況
然後ans加上最高位數字為1~T[len]-1的情況
接著以此類推,加上次最高位1~T[len-1]-1的情況,加上次次最高位1~T[len-2]-1的情況。。。。。。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cmath> 5using namespace std; 6 7 #define LL long long 8 9 int a,b; 10 LL f[20][10]; 11 12 LL solve(int t) 13 { 14 LL ans=0; 15 int len=0,T[20]; 16 while(t) 17 { 18 T[++len]=t%10; 19 t/=10; 20 } 21 for(int i=1;i<len;i++) 22 for(int j=1;j<=9;j++) 23 ans+=f[i][j]; 24 for(int i=1;i<T[len];i++) 25 ans+=f[len][i]; 26 for(int i=len-1;i>=1;i--) 27 { 28 for(int j=0;j<T[i];j++) 29 if(abs(j-T[i+1])>=2) 30 ans+=f[i][j]; 31 if(abs(T[i]-T[i+1])<2) break; 32 } 33 return ans; 34 } 35 36 int main() 37 { 38 scanf("%d %d",&a,&b); 39 for(int i=0;i<=9;i++) f[1][i]=1; 40 for(int i=2;i<=15;i++) 41 for(int j=0;j<=9;j++) 42 for(int k=0;k<=9;k++) 43 if(abs(k-j)>=2) 44 f[i][j]+=f[i-1][k]; 45 cout<<solve(b+1)-solve(a)<<endl; 46 return 0; 47 }
1026: [SCOI2009]windy數