定义 S ( k ) S(k) S(k)为 k k k的各个数位排序后的数字和
求 ∑ i = 1 x S ( i ) \sum\limits_{i=1}^xS(i) i=1∑xS(i)
考虑每个数字的贡献,只喝在第几位和出现多少次有关
那么我们定义 f [ i ] [ j ] [ q ] f[i][j][q] f[i][j][q]为枚举到第 i i i位,大于等于 j j j的数字出现了 q q q次的方案数
这个很容易用数位 d p dp dp来计算
那么可以做前缀和得到 s u m [ i ] [ x ] sum[i][x] sum[i][x]表示
有多少数字数位大于等于 x x x的出现次数大于等于 i i i次
那么 s u m [ i ] [ x ] − s u m [ i ] [ x + 1 ] sum[i][x]-sum[i][x+1] sum[i][x]−sum[i][x+1]就是 x x x在第 i i i位上出现的次数
这样就很容易计算答案(好难)
solve1的解法待补,这是solve2的解法
代码采用的是 d f s dfs dfs的写法会超时,需要改成递推版本。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9+7;
char s[709];
int f[709][709][11],sum[11][709],a[709],bit[709],n;//枚举到第i位,大于等于q的有j个,卡不卡上界
int dfs(int len,int num,int x,int limit)
{
if( len==0 ) return !num;
if( !limit&&f[len][num][x]!=-1 ) return f[len][num][x];
int lim = limit?a[len]:9,ans = 0;
for(int i=0;i<=lim;i++)
{
if( num==0&&i>=x ) continue;
ans += dfs(len-1,num-(i>=x),x,limit&&(i==a[len]) );
}
ans = ( ans%mod+mod )%mod;
if( !limit ) f[len][num][x] = ans;
return ans;
}
int solve1()
{
int res = 0;
for(int i=1;i<=9;++i)
for(int j=1,now=1;j<=n;++j,now=(10ll*now+1)%mod)
res = ( res+dfs(n,j,i,1)*now%mod )%mod;
return res;
}
int solve2()
{
for(int i=1;i<=n;i++)
for(int x=1;x<=9;x++)
for(int j=i;j<=n;j++)
sum[x][i] = ( sum[x][i]+dfs(n,j,x,1) )%mod;
int ans = 0;
for(int i=1;i<=n;i++)
for(int x=1;x<=9;x++)
{
int now = sum[x][i]-sum[x+1][i];
ans = ( ans+x*now*bit[i-1] )%mod;
}
return ( ans%mod+mod )%mod;
}
signed main()
{
memset( f,-1,sizeof f );
bit[0] = 1;
for(int i=1;i<=700;i++) bit[i] = bit[i-1]*10%mod;
cin >> (s+1);
n = strlen( s+1 );
for(int i=1;i<=n;i++) a[i] = s[n-i+1]-'0';
printf("%lld",solve2() );
}