题意:求出小于等于n的,满足三种情况的任意一种的数的个数:
①每个位数字,递增,如122
②每个位数字,递减,如211
③每个位数字,先递减,在递增,如121
题解:数位dp,记录三维,pos(枚举的位置),pre(前一个数是谁),st(当前是递增还是递减)
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define mod 1000000007
using namespace std;
typedef long long ll;
char a[105];
ll wei[105],l;
ll dp[105][15][5];
ll dfs(ll pos,ll pre,ll zt,ll flag)
{
if(pos<0)
{
if(zt==4)return 0;
return 1;
}
if(!flag&&dp[pos][pre][zt]!=-1)return dp[pos][pre][zt];
ll ma=flag?wei[pos]:9;
ll ans=0;
for(ll i=0;i<=ma;i++)
{
if((zt==3)&&pre<=i)ans=(ans+dfs(pos-1,i,zt,flag&&i==ma))%mod;
if(zt==2)
{
if(pre>=i)ans=(ans+dfs(pos-1,i,zt,flag&&i==ma))%mod;
else ans=(ans+dfs(pos-1,i,3,flag&&i==ma))%mod;
}
if(zt==4)
{
if(i==0)ans=(ans+dfs(pos-1,i,4,flag&&i==ma))%mod;
else ans=(ans+dfs(pos-1,i,2,flag&&i==ma))%mod;
}
}
if(!flag)dp[pos][pre][zt]=ans;
return ans;
}
int main()
{
ll T;
scanf("%lld",&T);
while(T--)
{
memset(dp,-1,sizeof(dp));
ll n;
scanf("%s",a);
l=strlen(a);
reverse(a,a+l);
ll mi=10;
for(ll i=0;i<l;i++)
{
wei[i]=a[i]-'0';
mi=min(mi,wei[i]);
}
ll ans=0;
ans=(ans+dfs(l-1,0,4,1))%mod;
printf("%lld\n",ans);
}
}