题解 CF520E 【Pluses everywhere】

思路:

(quad)这是一道数学题,分别计算每一个点分别作个位,十位... (n-k) 位的贡献即可(不可做这一数位的数的这一数位的贡献为 (0) ),如字符串 (9876543210)(0) 只可以作个位, (1) 只可以作个位和十位,其他数位的贡献为 (0) ,所以可以得到

(ans=a_n imes C_{n-1}^{k} + a_{n-1} imes C_{n-2}^{k-1} + 10 imes a_{n-1} imes C_{n-2}^k + a_{n-2} imes C_{n-2} + 10 imes a_{n-2} imes C_{n-3}^{k-1} + 100 imes a_{n-2} imes C_{n-3}^{k}.....)

化简得:

(ans =sum_{i=1}^{n-k}(10^{i-1} imes (a_{n-i-1} imes C_{n-i}^{k})+sum_{j=1}^{n-i}a_j imes C_{n-i-1}^{k-1}))

(quad)所以只需要用数组 (b) 记录前缀和,用数组 (d) 记录 (1! - n!) ,用数组 (inv) 记录每个阶乘的逆元,最后注意取模即可,很有价值的一题,建议式子再推一遍,尤其是边界。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
#define re register int
#define int long long
#define LL long long
#define il inline
#define lowbit(x) x&(-x)
#define next nee
#define inf 1e18
il int read()
{
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();
  while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  return x*f;
}
il void print(int x)
{
  if(x<0)putchar('-'),x=-x;
  if(x/10)print(x/10);
  putchar(x%10+'0');
}
const int N=1e5+5,MOD=1e9+7;
int n,m,k,a[N],b[N],inv[N]={1,1},ans,d[N]={1};
string s;
il int C(int a,int b){return d[a]*inv[b]%MOD*inv[a-b]%MOD;}
signed main()
{
  n=read();k=read();cin>>s;int ret=1;
  for(re i=1;i<=n;i++)a[i]=s[i-1]-'0',b[i]=a[i]+b[i-1],d[i]=d[i-1]*i%MOD;//计算前缀和,阶乘 1!-n!
  for(re i=2;i<=n;i++)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;//计算1-n每个数的逆元
  for(re i=2;i<=n;i++)inv[i]=inv[i]*inv[i-1]%MOD;计算1!-n!的逆元
  for(re i=1;i<=n-k;i++)
    {
      ans=(ans+ret*(a[n-i+1]*C(n-i,k)%MOD)%MOD)%MOD;
      ans=(ans+ret*(b[n-i]*C(n-i-1,k-1)%MOD)%MOD)%MOD;
      ret=ret*10%MOD; //ret表示10的i-1次方
      }
  print(ans);
  return 0;
}
原文地址:https://www.cnblogs.com/FarkasW/p/14027435.html