又是一個計數題,,
在n個數中間填加號,求所有方案的數字和。
下面提供兩種解法,題解的和來自FSY的。
題解:
考慮每個區間對數的貢獻,要麼沒有貢獻,要麼貢獻是10的冪。
故我們可以枚舉使得這個數的係數爲10^i時,區間的個數。發現是個組合數。
發現這樣枚舉實際上是固定了該點所在區間的右端點,也就是說固定了一個加號的位置。設當前點爲i,對i的貢獻爲10^j,則右端點爲i+j。
發現i~i+j不能填加號,共j個位置。而i+j右邊強制加了一個加號。所以剩下的加號方案爲
故貢獻爲
發現複雜度n^2,考慮交換枚舉順序。如果先枚舉j,即先枚舉區間右端點到點i的距離。
於是等差數列求和即可。
方法2:
考慮枚舉區間,計算區間被計算的次數。
在不考慮1和n兩個端點的情況下,考慮一個區間[l,r]。
使得這個區間存在的條件是區間左右各有一個加號,區間內部沒有加號。
所以加號的組合方案爲。故貢獻爲
發現複雜度爲n^2,發現組合數只跟區間長度len有關,考慮如何計算長度爲len的所有區間和。
舉例子時間:
如果有樣例abcdefg
發現長度爲1的和是a,b,c,d,e,f,g
長度爲2的是ab,bc,cd,de,ef,fg
也就是10*(a+b+c+d+e+f)+(b+c+d+e+f+g)。
多舉幾個例子,你會發現,對於一個長度len,其答案爲(len-1)的答案去掉最後一項*10,然後加上一個個位的後綴和。
所以維護後綴和然後該怎麼計算怎麼計算。
對於區間端點爲1或者n的,自己手玩一下該怎麼算,區別不大。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;ch=getchar();
}return cnt*f;
}
int fac[1000003],ifac[1000003];
int sum[1000003];
int suml[1000003];
int n,m;char ch[1000003];
const int mod=998244353;
int ksm(int a,int b){
int gu=1;
while(b){
if(b&1)gu=gu*a%mod;a=a*a%mod;b>>=1;
}return gu;
}
int jz[1000003];
int sumsuf[1000003];
int tem;
signed main(){
n=in;m=in;fac[0]=ifac[0]=1;jz[0]=1;
scanf("%s",ch+1);for(int i=1;i<=n;i++)jz[i]=jz[i-1]*10%mod;
for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;ifac[n]=ksm(fac[n],mod-2);
for(int i=n-1;i>=1;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
for(int i=1;i<=n;i++)sum[i]=(sum[i-1]*10+ch[i]-'0')%mod;
for(int i=n-1;i>=1;i--)sumsuf[i]=(sumsuf[i+1]+ch[i]-'0')%mod;
for(int i=2;i<=n-1;i++)suml[1]+=ch[i]-'0',suml[1]%=mod;
tem=suml[1]-ch[n-1]+'0';
for(int i=2;i<n;i++){
suml[i]=10*tem%mod+sumsuf[i+1];suml[i]%=mod;
tem=suml[i]-(sum[n-1]-sum[n-i-1]*jz[i]%mod)%mod;tem=(tem%mod+mod)%mod;
}`
// for(int i=1;i<=n;i++){
// cout<<suml[i]<<" ";
// }cout<<endl;
int ans=0;
for(int i=1;i<=n;i++){
int x=m-2,y=n-i-2;
if(x>y||x<0||y<0)continue;
// cout<<x<<" "<<y<<" "<<suml[i]<<" "<<fac[y]<<" "<<ifac[x]<<" "<<ifac[y-x]<<endl;
ans=(ans+suml[i]*fac[y]%mod*ifac[x]%mod*ifac[y-x]%mod)%mod;
//c/out<<ans<<endl;
}//cout<<ans<<endl;
for(int i=1;i<n;i++){
int x=m-1,y=n-1-i;if(x<0||y<0| |y<x)continue;
ans=(ans+sum[i]*fac[y]%mod*ifac[x]%mod*ifac[y-x]%mod)%mod;
}
//cout<<ans<<endl;
for(int i=2;i<=n;i++){
int x=m-1,y=i-2;if(x<0||y<0||y<x)continue;
// cout<<i<<" "<<sum[n]<<" "<<sum[i-1]<<" "<<jz[n-i+1]<<" "<<sum[n]-sum[i-1]*jz[n-i+1]<<endl;
ans=(ans+(sum[n]-sum[i-1]*jz[n-i+1]%mod+mod)%mod*fac[y]%mod*ifac[x]%mod*ifac[y-x]%mod)%mod;
}
// ans=(ans+sum[n]*(m==0)+mod)%mod;
cout<<ans;
return 0;
}