题意
现在要给一个长度为n数字串上面加上恰好k个加号,把所有可能的算术结果相加起来。
加号加到数字串中间之后要形成正确的算术表达式。规则是:没有两个加号连在一起,两个加号之间至少要有一位数字,加号不能加在开头,也不能加在结尾。比如数字串是10500,那么100500(加0个加号),1+00+500 或者 10050+0 这些放置的加号都是合法的,而100++500, +1+0+0+5+0+0 和100500+都是非法的。
结果比较大,对 109+7 取余输出即可。
题解
不难的题,想了一会就想出来了,哈哈
O(n^2)的做法
枚举一个区间
然后排列组合算次数
O(n)的做法
考虑每一位对于答案的贡献
也就是第i位,,他是
100,101,102....10k
10
0
,
10
1
,
10
2
.
.
.
.10
k
分别有多少种情况
然后发现,除了这一位所能表示的最大,别的都是常数啊
然后这个可以预处理,最后一个判断一下就可以了
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const LL N=1000005;
LL n,k;
LL JC[N],inv[N];
LL sum=0;
LL pow (LL x,LL y)
{
if (y==1) return x;
LL lalal=pow(x,y>>1);
lalal=lalal*lalal%MOD;
if (y&1) lalal=lalal*x%MOD;
return lalal;
}
LL lalal[N];//前缀和
LL C (LL x,LL y)
{
if (x<y) return 0;
if (y==0) return 1;
if (x==y) return 1;
return JC[x]*inv[y]%MOD*inv[x-y]%MOD;
}
int main()
{
scanf("%lld%lld",&n,&k);
JC[1]=1;for (LL u=2;u<=n;u++) JC[u]=JC[u-1]*u%MOD;
inv[n]=pow(JC[n],MOD-2);for (LL u=n-1;u>=1;u--) inv[u]=inv[u+1]*(u+1)%MOD;
LL o=1;
for (LL u=1;u<=n;u++)
{
// printf("%lld %lld %lld\n",n-u,k-1,C(n-u,k-1));
lalal[u]=lalal[u-1]+C(n-u-1,k-1)*o%MOD;
lalal[u]%=MOD;
o=o*10%MOD;
}
LL ans=0;
o=1;
for (int u=1;u<n;u++) o=o*10%MOD;
LL INV=pow(10,MOD-2);
for (LL u=1;u<=n;u++)
{
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
ans=ans+lalal[n-u]*(ch-'0');
ans=ans+C(u-1,k)*o%MOD*(ch-'0');
ans%=MOD;
/*printf("%lld\n",lalal[n-u]);
printf("%lld\n",ans);*/
o=o*INV%MOD;
}
printf("%lld\n",ans);
return 0;
}