题目概述
一个正整数是 Valley Number 需要满足没有任何一段数字出现先递增后递减(这里的递增和递减都不是严格的)的情况。
求 ≤n 的 Valley Number 的数量。
解题报告
显然是数位DP,但是我刚开始想了一个很有病的定义,样例都没调出来TAT。
定义
f[i][j][t]
表示前
i
个数中第
先预处理出
Sum(i)
表示长度为
1
~
示例程序
请读者老爷原谅我这么乱的代码(数位DP代码总是很乱),DP(L,R)表示求
f[L]
~
f[R]
。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=100,MOD=1000000007;
int te,n,a[maxn+5],f[maxn+5][10][2],sum[maxn+5];
#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)
int check(int k,int t,int j)
{
if (t) if (k>j) return -1; else return 1;
if (!t) if (k<j) return 1; else return 0;
}
void AMOD(int &x,int tem) {x+=tem;if (x>MOD) x-=MOD;}
void DP(int L,int R)
{
for (int i=L;i<=R;i++)
for (int k=0;k<=9;k++)
for (int t=0;t<=1;t++) if (f[i-1][k][t])
for (int j=0;j<=9;j++)
{
int x=check(k,t,j);if (x==-1) continue;
AMOD(f[i][j][x],f[i-1][k][t]);
}
}
void Make()
{
for (int i=1;i<=maxn;i++)
{
sum[i]=sum[i-1];memset(f,0,sizeof(f));
for (int j=1;j<=9;j++) f[1][j][0]=1;DP(2,i);
for (int j=0;j<=9;j++) AMOD(sum[i],f[i][j][0]),AMOD(sum[i],f[i][j][1]);
}
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (Make(),scanf("%d",&te);te;te--)
{
char ch=getchar();while (Eoln(ch)) ch=getchar();
n=0;while (!Eoln(ch)) a[++n]=ch-48,ch=getchar();
int ans=sum[n-1];memset(f,0,sizeof(f));
for (int j=1;j<a[1];j++) f[1][j][0]=1;DP(2,n);
for (int j=0;j<=9;j++) AMOD(ans,f[n][j][0]),AMOD(ans,f[n][j][1]);
int fl=0;
for (int p=1;p<n;p++)
{
if (p>1) fl=check(a[p-1],fl,a[p]);if (fl==-1) break;
memset(f,0,sizeof(f));f[p][a[p]][fl]=1;
for (int j=0,x;j<a[p+1];j++) if (~(x=check(a[p],fl,j))) f[p+1][j][x]=1;
DP(p+2,n);for (int j=0;j<=9;j++) AMOD(ans,f[n][j][0]),AMOD(ans,f[n][j][1]);
}
if (~fl&&n>1) fl=check(a[n-1],fl,a[n]);if (~fl) AMOD(ans,1);
printf("%d\n",ans);
}
return 0;
}