CodeForces-520E Pluses everywhere

题目描述

给出一个长度为 \(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;
}

转载于:https://www.cnblogs.com/dsjkafdsaf/p/11402180.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值