2017廣東工業大學程式設計競賽決賽 Problem G: 等凹數字(迴文+數位dp)
阿新 • • 發佈:2018-12-26
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));
}
}