题目大意:
定义f(x)为把x的各个数位排完序之后的新数,求 ∑ni=1f(i) ∑ i = 1 n f ( i )
思路:
n的范围有
10700
10
700
,所以考虑用数位DP来解决问题。
这里的数位DP即每次枚举下一位要添加的数然后转移,但是无法计算答案。
考虑如何计算答案,对于一个排完序之后形成的新数,例如
34559
34559
,可以看成是总共有
9
9
层的数,然后每一层都是的形式,不断地加上来的,即
3×11111+1×1111+1×111+4×1
3
×
11111
+
1
×
1111
+
1
×
111
+
4
×
1
。
于是我们把状态记录为每一个数字它需要加上的这样的
11…1
11
…
1
的个数,即记录状态dp[i][j][k][0/1]表示前i个数,在数字j这里要加上k个
11…1
11
…
1
,是否封顶的个数即可。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("CF908G.in","r",stdin);
freopen("CF908G.out","w",stdout);
}
const int maxn=700+10;
const ll mod=1e9+7;
int len;
char n[maxn];
ll dp[maxn][15][maxn][2],p[maxn],ans;
void init(){
scanf("%s",n+1);
len=strlen(n+1);
REP(i,1,len)p[i]=(p[i-1]*10+1)%mod;
}
void add(ll &_,ll __){_=_+__;if(_>mod)_-=mod;}
void work(){
REP(i,1,9)dp[0][i][0][1]=1;
REP(i,0,len)REP(j,1,9)REP(k,0,i){
REP(f,0,9){
if(f+'0'<=n[i+1]){
if(f+'0'<n[i+1])add(dp[i+1][j][k+(f>=j)][0],dp[i][j][k][1]);
else{
add(dp[i+1][j][k+(f>=j)][1],dp[i][j][k][1]);
}
}
add(dp[i+1][j][k+(f>=j)][0],dp[i][j][k][0]);
}
if(i==len){
ll val=(dp[i][j][k][0]+dp[i][j][k][1])*p[k]%mod;
add(ans,val);
}
}
printf("%lld\n",ans);
}
int main(){
//File();
init();
work();
return 0;
}