Codeforces 520E/521C Pluses everywhere

来源:互联网 发布:淘宝客服电话人工按几? 编辑:程序博客网 时间:2024/06/05 03:44

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

给定长度为n的数字串,在空隙添上k个+号(每个空隙最多添加一个),得到合法的加法式子,求上述得到的所有的式子的计算结果之和%1e9+7
(0k<n1e5)

思路

考虑每个数字对答案的贡献值,总共有n-1个位置可以放加号。下文中左边指高位,右边指地位。
对于一个数字x来说,考虑以下情况:

  • 考虑其作个位时,也就是其右边第一个空隙为加号,那么其余k-1个加号随便放在剩下的n-2个位置就好了,这时对答案的贡献为x;
  • 其作十位数的时候,那么加号一定在其右边第二个空隙上,其余k-1个加号随便放在剩下的n-3个位置(除去x右边第一个空隙)就好了,这时对答案的贡献为10x
  • 以此类推……
  • 还有一种情况就是加号全部放在x的左边,这时对答案的贡献要根据x的位置来决定

但是问题来了,这样会使得复杂度成为O(n2),显然不行
不过你会发现,上述过程有好多重复的工作,对于每个数考虑其右边第一个加号时过程几乎是一样的,只是考虑的次数不同,这样完全可以利用前面算出来的结果,求个前缀和,接着累加就行

最后的问题就是求组合数,提前处理好1~n的阶乘以及对1e9+7的逆元就好了


具体代码如下:
Result:Accepted    Memory:5272 KB   Time : 46ms

#include<bits/stdc++.h>const int maxn = 1e5+5;const int mod = 1e9+7;using namespace std;typedef long long ll;ll fac[maxn];ll inv[maxn];ll sum[maxn];char s[maxn];ll a[maxn];int n,k;ll ans;ll ten;ll mod_pow(ll x,ll n){    x%=mod;    ll res = 1;    while(n>0)    {        if(n&1) res = res*x%mod;        x = x*x%mod;        n>>=1;    }    return res;}void init(){    inv[0]=1;fac[0]=1;    for(int i=1;i<=n;i++)    {        fac[i] = (fac[i-1]*i)%mod;        inv[i] = mod_pow(fac[i],mod-2)%mod;    }}ll C(ll n,ll m){    if(n<0||m<0) return 0;    if(m>n) return 0;    return (((fac[n]*inv[m])%mod)*inv[n-m])%mod;}int main(){    cin>>n>>k;    init();    scanf("%s",s+1);    for(int i=1;i<=n;i++)        a[i] = s[i]-'0';    ten = 1;    for(int i=n-1;i>=1;i--)    {        sum[i] = (sum[i+1]+ten*C(i-1,k-1))%mod;        //枚举右边第一个加号式,利用前面的计算结果        ten = (ten*10)%mod;    }    ten = 1;    for(int i=n;i>=k+1;i--)    {        sum[i] = (sum[i]+C(i-1,k)*ten)%mod;//考虑加号全部在左边        ten = (ten*10)%mod;    }    ans = 0;    for(int i=1;i<=n;i++)        ans = (ans+sum[i]*a[i])%mod;    cout<<ans<<endl;}
原创粉丝点击