题面:hdu6148
比赛的时候调到快结束的时候才A掉。。。(我真是太弱了。。。
其实就是数位DP,状态也很简单:
f[i][j][k]
表示i位数字开头数字为j,当前状态为k的数量,k=1表明已经有过递增,k=0表明没有过递增。。。
然后先把f求出来之后直接统计答案就行了
还是很简单的。。。要是早调出来几分钟说不定文化衫就有了呢QAQ
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <ctime>
#include <map>
#include <queue>
#include <cstdlib>
#include <string>
#include <climits>
#include <set>
#include <vector>
#define int long long
using namespace std;
const int MOD=1e9+7;
int f[1010][10][2];
char s[1010];
inline int dp(){
scanf("%s",s+1);int l=strlen(s+1);
if(l==1)return s[1]-'0';
int ans=0;
for(int i=1;i<l;i++)
for(int j=1;j<10;j++)(ans+=f[i][j][0]+f[i][j][1])%=MOD;
int flag=0;
for(int i=1;i<l;i++){
int now=s[i]-'0';
for(int j=0;j<now;j++)if(i!=1||j!=0){
if(flag==1&&j-s[i-1]+'0'<0)continue;
(ans+=f[l-i+1][j][0])%=MOD;
if((i==1)||(!flag&&j-s[i-1]+'0'<=0))(ans+=f[l-i+1][j][1])%=MOD;
}
if((i>1)&&s[i]-s[i-1]<0&&flag){flag=2;break;}
if((i>1)&&s[i]-s[i-1]>0)flag=1;
}
if(flag<2){
int now=s[l]-'0';
if(flag<2)for(int j=0;j<=now;j++){
if(flag==1&&j-s[l-1]+'0'<0)continue;
(ans+=f[1][j][0])%=MOD;
}
}
return ans;
}
signed main()
{
for(int i=0;i<10;i++)f[1][i][0]=1;
for(int i=2;i<=100;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++){
if(j>k)(f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1])%=MOD;
if(j==k)(f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1])%=MOD;
if(j<k)(f[i][j][0]+=f[i-1][k][0])%=MOD;
}
int T;scanf("%I64d",&T);
while(T--)printf("%I64d\n",dp());
return 0;
}