1. 程式人生 > 實用技巧 >題解 CF520E 【Pluses everywhere】

題解 CF520E 【Pluses everywhere】

思路:

\(\quad\)這是一道數學題,分別計算每一個點分別作個位,十位... \(n-k\) 位的貢獻即可(不可做這一數位的數的這一數位的貢獻為 \(0\) ),如字串 \(9876543210\)\(0\) 只可以作個位, \(1\) 只可以作個位和十位,其他數位的貢獻為 \(0\) ,所以可以得到

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

化簡得:

\(ans =\sum_{i=1}^{n-k}(10^{i-1}\times (a_{n-i-1}\times C_{n-i}^{k})+\sum_{j=1}^{n-i}a_j\times 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;
}