1. 程式人生 > >2017廣東工業大學程式設計競賽決賽 Problem G: 等凹數字(迴文+數位dp)

2017廣東工業大學程式設計競賽決賽 Problem G: 等凹數字(迴文+數位dp)

Problem G: 等凹數字
Description
定義一種數字稱為等凹數字,即從高位到地位,每一位的數字先非遞增再非遞減,不能全部數字一樣,且該數是一個迴文數,即從左讀到右與從右讀到左是一樣的,僅形成一個等凹峰,如543212345,5544334455是合法的等凹數字,543212346,123321,111111不是等凹數字。現在問你[L,R]中有多少等凹數字呢?

Input
第一行一個整數T,表示資料的組數。
接下來T行每行倆個數字L和R,(1<=L<=R<=1e18)
Output
輸出一個整數,代表[L,R]中有多少等凹數字
Sample Input
2
1 100
101 200
Sample Output
0
1
HINT

小於等於2位的數字無凹峰

套上回文數位dp模板,加上4個維度(上升,下降,前導0,前一個數)看了一下別人解題思路,知道多開這幾維才寫出來QAQ
程式碼裡有自己的註釋
AC程式碼

#include<stdio.h>
#include<string.h>
int degth[20];
int temp[20];
long long dp[20][20][10][3][3][3];
long long dfs(int pos,int len,int pre,int up,int down,int flag,int f,int k)//長度,當前位,前一位,上升,下降,迴文 
{
    if
(len<0) return up&&down&&flag; //上升加下降加是迴文 if(!f&&dp[pos][len][pre][up][down][flag]!=-1&&!k) return dp[pos][len][pre][up][down][flag]; int max=f?degth[len]:9; long long ret=0; for(int i=0;i<=max;i++) { temp[len]=i; if(k) //前導0時直接降低長度,否則執行下一位(因為起始位無法判斷上升和下降)
ret+=dfs(pos-(k&&i==0),len-1,i,0,0,flag,f&&i==max,k&&i==0); else if(pre==i) { if(flag&&(pos+1)/2>len) ret+=dfs(pos,len-1,i,up,down,i==temp[pos-len],f&&i==max,k&&i==0); else ret+=dfs(pos,len-1,i,up,down,flag,f&&i==max,k&&i==0); } else if(pre<i)//遞增 { if(!down) continue; //沒有下降就上升 if(flag&&(pos+1)/2>len) ret+=dfs(pos,len-1,i,1,down,i==temp[pos-len],f&&i==max,k&&i==0); else ret+=dfs(pos,len-1,i,1,down,flag,f&&i==max,k&&i==0); } else if(pre>i)//遞減 { if(up) continue;//已經上升過 if(flag&&(pos+1)/2>len) ret+=dfs(pos,len-1,i,up,1,i==temp[pos-len],f&&i==max,k&&i==0); else ret+=dfs(pos,len-1,i,up,1,flag,f&&i==max,k&&i==0); } } if(!f&&!k) dp[pos][len][pre][up][down][flag]=ret; return ret; } long long solve(long long x) { int len=0; while(x) { degth[len++]=x%10; x/=10; } return dfs(len-1,len-1,0,0,0,1,1,1); } int main() { memset(dp,-1,sizeof(dp)); int T; scanf("%d",&T); while(T--) { long long l,r; scanf("%lld%lld",&l,&r); printf("%lld\n",solve(r)-solve(l-1)); } }