链接
题意:
给出一个数位为 n n n的数字 ( n < = 1 e 6 ) ( n < = 1 e 6 ) (n<=1e6),现在可以将该数字最多分成 k ( 1 < = k < = n ) k ( 1 < = k < = n) k(1<=k<=n)段。定义一种分法的贡献为所有段的数字之和,求所有分法的贡献和。
例如对于样例,答案为 1 + 1 + 10 + 100 = 112 1 + 1 + 10 + 100 = 112 1+1+10+100=112
分析:
首先我们肯定算每位数字对答案产生的贡献。
但是我们能够发现每一位做出的贡献从x,x10,x100,x*1000,这个会很影响我们思考问题的结果。
如果我们看一个序列
.
.
.
.
i
j
.
.
.
....ij...
....ij...,
i
i
i处于
x
x
x位上,那么
j
j
j处于
x
−
1
x-1
x−1位上(我们从各位开始记数)。那么
j
j
j可以做的位(也就是乘的10的次方)
i
i
i也一定可以做,并且
i
i
i还比
j
j
j多一个
1
0
i
10^i
10i.有点绕慢慢理解。
举个例子。123456。
抛开几段的限制
6的贡献只能是61
5的贡献可以是5(1+10)
4的贡献是4*(1+10+100)
…
这样是不是好理解点了。
然后我们看 k k k段的限制。如果我们看当前 i i i位值贡献计算 1 0 j 10^j 10j那么在 i + j i+j i+j位置一定有一个挡板也就是从此分段,那么有三种情况。
- i + j > n i+j>n i+j>n贡献为0,越位了。
- i + j = = n i+j==n i+j==n贡献是 ∑ i = 0 k − 1 C n − j − 1 i \sum_{i=0}^{k-1}C_{n-j-1}^{i} ∑i=0k−1Cn−j−1i ( C n − j − 1 i C_{n-j-1}^{i} Cn−j−1i表示确定了j位置,在剩下的{n-j-1}中找出i段,为什么是(k-1)哪?i+j=n这最后算一段)
- i + j < n i+j<n i+j<n贡献是 ∑ i = 0 k − 2 C n − j − 1 i \sum_{i=0}^{k-2}C_{n-j-1}^{i} ∑i=0k−2Cn−j−1i (为什么上面是 k − 1 k-1 k−1这个地方又成了 k − 2 k-2 k−2,因为上面是分出来后,那一段就是端点,而这个是一切三段,固定中间1段。)
那么我们就需要预处理出来 ∑ i = 0 k − 1 C n − j − 1 i \sum_{i=0}^{k-1}C_{n-j-1}^{i} ∑i=0k−1Cn−j−1i.
∑
i
=
0
x
C
n
i
=
∑
i
=
0
x
−
1
C
n
i
+
C
n
x
\sum_{i=0}^{x}C_{n}^{i}=\sum_{i=0}^{x-1}C_{n}^{i}+C_{n}^{x}
∑i=0xCni=∑i=0x−1Cni+Cnx
这个递推式子可以实现。
我们看组合数定理:
C
n
m
=
C
n
−
1
m
+
C
n
−
1
m
−
1
C_n^m=C_{n-1}^m+C_{n-1}^{m-1}
Cnm=Cn−1m+Cn−1m−1
∑
i
=
0
x
C
n
i
=
C
n
0
+
C
n
1
+
C
n
2
.
.
.
+
C
n
x
\sum_{i=0}^{x}C_{n}^{i}=C_{n}^{0}+C_{n}^{1}+C_{n}^{2}...+C_{n}^{x}
∑i=0xCni=Cn0+Cn1+Cn2...+Cnx
利用上面的组合数定理:
C
n
−
1
−
1
+
C
n
−
1
0
+
C
n
−
1
0
+
C
n
−
1
1
+
C
n
−
1
1
+
.
.
.
.
+
C
n
−
1
x
−
1
+
C
n
−
1
x
−
1
+
C
(
n
−
1
)
x
C_{n-1}^{-1}+C_{n-1}^{0}+C_{n-1}^{0}+C_{n-1}^{1}+C_{n-1}^{1}+....+C_{n-1}^{x-1}+C_{n-1}^{x-1}+C_(n-1)^{x}
Cn−1−1+Cn−10+Cn−10+Cn−11+Cn−11+....+Cn−1x−1+Cn−1x−1+C(n−1)x
=
2
∑
i
=
0
x
C
n
−
1
i
−
C
n
−
1
x
=2\sum_{i=0}^{x}C_{n-1}^{i}-C_{n-1}^{x}
=2i=0∑xCn−1i−Cn−1x
递推式子也有了。
ll qpow(ll a, ll b)
{
ll ans = 1;
while(b)
{
if(b & 1) ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
ll n, k;
ll qpow10[maxn], a[maxn], b[maxn];
ll fac[maxn];
void init()
{
fac[0] = qpow10[0] = 1;
for(int i = 1; i < maxn; i++)
{
fac[i] = fac[i - 1] * i % mod;
qpow10[i] = qpow10[i - 1] * 10 % mod;
}
}
ll infac(ll x)
{
return qpow(x, mod - 2);
}
ll C(ll n, ll m)
{
if(n < m) return 0;
return fac[n] * infac(fac[m]) % mod * infac(fac[n - m]) % mod;
}
//string str;
char str[maxn];
void solve()
{
scanf("%lld %s",&k,str+1);
n=strlen(str+1);
a[0] = (k - 2 >= 0) ? 1 : 0;
b[0] = (k - 1 >= 0) ? 1 : 0;
for(ll i = 1; i < n; i++)
{
a[i] = (2 * a[i - 1] - C(i - 1, k - 2) + mod) % mod;
b[i] = (2 * b[i - 1] - C(i - 1, k - 1) + mod) % mod;
}
ll ans = 0, sum = 0;
for(ll i = n; i >= 1; i--)
{
ll tmp = str[i] - '0';
if(i != n)
{
sum = (sum + a[i - 1] * qpow10[n - i - 1]) % mod;
}
ans = (ans + tmp * (b[i - 1] * qpow10[n - i] % mod + sum)) % mod;
}
cout << ans << endl;
}