C. Bargain
Description
Sometimes it is not easy to come to an agreement in a bargain. Right now Sasha and Vova can’t come to an agreement: Sasha names a price as high as possible, then Vova wants to remove as many digits from the price as possible. In more details, Sasha names some integer price n, Vova removes a non-empty substring of (consecutive) digits from the price, the remaining digits close the gap, and the resulting integer is the price.
For example, is Sasha names 1213121, Vova can remove the substring 1312, and the result is 121.
It is allowed for result to contain leading zeros. If Vova removes all digits, the price is considered to be 0.
Sasha wants to come up with some constraints so that Vova can’t just remove all digits, but he needs some arguments supporting the constraints. To start with, he wants to compute the sum of all possible resulting prices after Vova’s move.
Help Sasha to compute this sum. Since the answer can be very large, print it modulo 109+7.
Input
The first and only line contains a single integer n ( 1 ≤ n < 1 0 1 0 5 1≤n<10^{10^5} 1≤n<10105).
Output
In the only line print the required sum modulo 109+7.
Examples
input
107
output
42
input
100500100500
output
428101984
Note
Consider the first example.
Vova can choose to remove 1, 0, 7, 10, 07, or 107. The results are 07, 17, 10, 7, 1, 0. Their sum is 42.
题意: 给定一个数,求从它的任意位置删掉任意数后的所有情况的和。
题解: 我们可以对每一个数字逐个讨论,对于数字3,如果其有对最终结果做出贡献(即没有被去除的情况下),则有两种情况:①被去除的子串在3之前;②被除去的子串在3后面。
· 如果是第①种情况,3所占的位数始终是不变的,都是千位。共有6种可能:
其中数字3做出的贡献就是3000×6=18000。而这个6是怎么来的呢?显然就是3+2+1=6。总结一下就是,对于下标为i(下标从0开始,从后往前遍历,总长设为len)的数字,第①种情况共有(len-i)(len-i-1)/2
种可能,做出的贡献为(s[i]-‘0’)pow(10,i)(len-i)(len-i-1)/2
,其中s是Sasha给出的价格,为字符串类型。
· 如果是第②种情况,同样有6种可能:
数字3做出的贡献就是3×(3×100+2×10+1)=3×321=963(这里我们只看3所处的位置,不看其他数)。看着似乎也有些规律,来分析一下:如果一开始数字3后面有四个数,那么原式中的321就会变成4321。因此我们可以用变量sum来保存当前的要乘以的数,那么相对于下标为i的数字,做出的贡献为(s[i]-‘0’)sum
,而每次循环之后sum如何变化,下面再讲。
这样我们就可以计算出每个数字对结果的贡献。但是还有一个问题,Sasha给出的价格的范围为
1
≤
n
<
1
0
5
1≤n<10^5
1≤n<105,根本没法计算,比如在第①种情况,(s[i]-‘0’)pow(10,i)(len-i)(len-i-1)/2
中的pow(10,i)直接挂掉。这个时候我们就要对一些像10,100,1000之类的数字先做一遍取余,保存在数组f中,f[i]就表示pow(10,i)取余之后的结果,这样代码就会变成(len-i)(len-i-1)/2%MODf[i]*(s[i]-‘0’)%MOD;
。而在第②种情况,sum显然也会挂掉,所以每次在更新sum的时候,也要对sum进行取余。而sum要如何变化呢?答案就是sum=((i+1)*f[i]%MOD+sum)%MOD
;,想象从321到4321的过程,你一定能看懂这段代码。
c++ AC 代码
#include <cstdio>
#include <cstring>
#include <iostream>
typedef long long ll;
using namespace std;
const int mod = 1e9 + 7, N = 1e5 + 10;
char str[N];
int main()
{
cin >> (str + 1);
ll length = strlen(str + 1);
ll ans = 0;
ll pw = 1;
ll sum = 0;
for (ll i = length; i >= 1; i--)
{
ll num = i * (i - 1) / 2;
ans = (ans % mod + (str[i] - '0') * pw % mod * num % mod) % mod; // 第一种情况
ans = (ans % mod + (str[i] - '0') % mod * sum % mod) % mod; // 第二种情况
sum = (sum % mod + (length - i + 1) * pw % mod) % mod;
pw = pw * 10 % mod;
}
cout << ans << endl;
return 0;
}