传送门

定义 S ( k ) S(k) S(k) k k k的各个数位排序后的数字和

∑ i = 1 x S ( i ) \sum\limits_{i=1}^xS(i) i=1xS(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() );
}