题目描述
给出一个长度为 \(n\) 的字符串,给出一个非负整数 \(k\),要求给这个字符串中间添加 \(k\) 个$\(+\)’号,变成一个表
达式,比如”\(1000101\)”,添加两个\(+\)号,可以变成”\(10+001+01\)”,或者”\(1000+1+01\)”,表达式的值分别是\(12\) 和 \(1002\)。
问所有的添加加号的方案的表达式的值的和是多少。
Input
两个整数 \(n,k\),一个字符串$ s$ \((0<=k<n<=1e5).\)
Output
一个整数,模$ 1000000007$
Sample Input
3 1
108
3 2
108
Sample Output
27
9
计数\(DP\)
首先,看到那么大的数据范围肯定是对于每个数计算贡献。
那么我们该如何计算贡献呢?
对于题目给出的那个字符串\(S\),从左往右每个数字依次为\(a_{n-1},a_{n-2}....a_{1},a_0\).
现在,我们对于\(a_t\),讨论其贡献。
\(a_t\)右边有\(t\)个位置可以放置加号,同时一共有\(n-1\)个位置放置加号。
若\(a_t\)右边第一个位置放置了加号,则\(a_t\)被当成个位,还有\(n-2\)个空位,\(k-1\)个加号,一共有\(C(k-1,n-2)\)种方案。
其贡献为\(C(k-1,n-1)*10^{0}*a_t\)。
若\(a_t\)右边第一个位置为空,第二个位置放置加号,则\(a_t\)为十位,还有\(n-3\)个空位,\(k-1\)个加号,共有\(C(k-1,n-3)\)种方案。
贡献为\(C(k-1,n-2)*10^{1}*a_t\).
依次类推,
若\(a_t\)右边为空,则贡献为\(C(k,n-t-2)*10^{t}*a_t\)。
所以,\(a_t\)这个数的贡献为\((10^{t}*C(k,n-t-2)+\sum^{t}_{j=0}10^{j}*C(k-1,n-j-2))*a_t\)。
于是我们可以得到第\(i\)个数的贡献计算公式\(A_i=10^{i}*C(k,n-i-2)+\sum^{i}_{j=0}10^{j}*C(k-1,n-j-2)\)。
最后,\(Ans=\sum^{n-1}_{i=0}A_i*a_i\)。
代码如下
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
#define reg register
#define Raed Read
#define clr(a,b) memset(a,b,sizeof a)
#define Mod(x) (x>=mod)&&(x-=mod)
#define debug(x) cerr<<#x<<" = "<<x<<endl;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define rep(a,b,c) for(reg int a=(b),a##_end_=(c); a<=a##_end_; ++a)
#define ret(a,b,c) for(reg int a=(b),a##_end_=(c); a<a##_end_; ++a)
#define drep(a,b,c) for(reg int a=(b),a##_end_=(c); a>=a##_end_; --a)
#define erep(i,G,x) for(int i=(G).Head[x]; i; i=(G).Nxt[i])
#pragma GCC target("avx,avx2,sse4.2")
#pragma GCC optimize(3)
inline int Read(void) {
int res=0,f=1;
char c;
while(c=getchar(),c<48||c>57)if(c=='-')f=0;
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>=48&&c<=57);
return f?res:-res;
}
template<class T>inline bool Min(T &a, T const&b) {
return a>b?a=b,1:0;
}
template<class T>inline bool Max(T &a, T const&b) {
return a<b?a=b,1:0;
}
const int N=1e5+5,M=1e6+5,mod=1e9+7;
bool MOP1;
int Fac[N],Inv[N];
inline int Pow(int x) {
int res=1,y=mod-2;
while(y) {
if(y&1)res=(res*x)%mod;
x=(x*x)%mod,y>>=1;
}
return res;
}
inline int C(int x,int y) {
if(!x)return 1;
return (Fac[y]*((Inv[x]*Inv[y-x])%mod))%mod;
}
int A[N],Pow_10[N];
char S[N];
bool MOP2;
inline void _main() {
int n=Read(),k=Read(),Ans=0,tot=0;
scanf("%s",S),Fac[0]=Pow_10[0]=Inv[0]=1;
if(!k) {
int Ans=0;
ret(i,0,n)Ans=(Ans*10+(S[i]^48))%mod;
printf("%lld\n",Ans);
return;
}
rep(i,1,n) {
Fac[i]=(Fac[i-1]*i)%mod;
Pow_10[i]=(Pow_10[i-1]*10)%mod;
Inv[i]=Pow(Fac[i]);
}
A[0]=C(k-1,n-2);
int P=n-k-1;
rep(i,0,P)A[i]=(A[i-1]+Pow_10[i]*C(k-1,n-i-2))%mod;
rep(i,P+1,n)A[i]=A[i-1];
rep(i,0,P)A[i]=(A[i]+Pow_10[i]*C(k,n-i-2));
ret(i,0,n)Ans=(Ans+(S[i]^48)*A[n-i-1])%mod;
printf("%lld\n",Ans);
}
signed main() {
_main();
return 0;
}