[数学记录]Loj#6503. 「雅礼集训 2018 Day4」Magic

command_block

2020-11-03 07:15:29

Personal

**题意** :有 $m$ 种小球,每种小球有 $a[i]$ 个,一共有 $\sum a[i] = n$ 个小球. 把它们排成一排 ,求恰有 $k$ 对相邻的小球种类相同的方案数。 答案对 $998244353$ 取模。 $m\leq 2\times 10^4.n\leq 2\times 10^5$ ,时限$\texttt{1s}$。 ------------ 考虑钦定 $k$ 个相邻相同关系,最后反演。 那么,若 $a$ 个同类小球最终在序列里产生 $t$ 次相邻相同,则相当于分成了 $a-t$ 个连续段,不妨直接视作 $a-t$ 个球。 对于一类大小为 $a$ 的球 ,将其分成 $i$ 段的方案书可用夹板法计算,为 $\dbinom{a-1}{i-1}$ 枚举其缩成多少段,可得其 $\rm EGF$ 为 $\sum\limits_{i=1}^{a}\dfrac{\binom{a-1}{i-1}x^i}{i!}$ 用分治 $\rm FFT$ 将各个球的 $\rm EGF$ 卷积起来。 钦定 $k$ 个相邻相同关系时,会缩成 $n-k$ 段,即 $[x^{n-k}]$ 项系数。 设 $f(k)$ 为钦定 $k$ 个相邻相同的方案数,$g(k)$ 为恰有 $k$ 个相邻相同的方案数。 则有 $f(k)=\sum\limits_{i=k}^{n-1}\dbinom{i}{k}g(i)\Rightarrow g(k)=\sum\limits_{i=k}^{n-1}\dbinom{i}{k}(-1)^{i-k}f(k)$。 复杂度 $O(n\log^2n)$。 ```cpp #include<algorithm> #include<cstring> #include<cstdio> #define ll long long #define ull unsigned long long #define clr(f,n) memset(f,0,sizeof(int)*(n)) #define cpy(f,g,n) memcpy(f,g,sizeof(int)*(n)) using namespace std; const int _G=3,mod=998244353,Maxn=135000; ll powM(ll a,ll t=mod-2){ ll ans=1; while(t){ if(t&1)ans=ans*a%mod; a=a*a%mod;t>>=1; }return ans; } ll fac[Maxn],ifac[Maxn]; ll C(int n,int m) {return fac[n]*ifac[m]%mod*ifac[n-m]%mod;} void Init(int n) { fac[0]=1; for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod; ifac[n]=powM(fac[n]); for (int i=n;i;i--) ifac[i-1]=ifac[i]*i%mod; } const int invG=powM(_G); int tr[Maxn],tf; void tpre(int n){ if (tf==n)return ;tf=n; for(int i=0;i<n;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0); } void NTT(int *g,bool op,int n) { tpre(n); static ull f[Maxn],w[Maxn]={1}; for (int i=0;i<n;i++)f[i]=(((ll)mod<<5)+g[tr[i]])%mod; for(int l=1;l<n;l<<=1){ ull tG=powM(op?_G:invG,(mod-1)/(l+l)); for (int i=1;i<l;i++)w[i]=w[i-1]*tG%mod; for(int k=0;k<n;k+=l+l) for(int p=0;p<l;p++){ int tt=w[p]*f[k|l|p]%mod; f[k|l|p]=f[k|p]+mod-tt; f[k|p]+=tt; } }if (!op){ ull invn=powM(n); for(int i=0;i<n;++i) g[i]=f[i]%mod*invn%mod; }else for(int i=0;i<n;++i)g[i]=f[i]%mod; } void px(int *f,int *g,int n) {for(int i=0;i<n;++i)f[i]=1ll*f[i]*g[i]%mod;} int _o[Maxn],*tbuf=_o; struct Poly{int len,*f;}a[Maxn]; Poly times(Poly A,Poly B) { static int t1[Maxn],t2[Maxn],t3[Maxn]; int len=A.len+B.len-1; if (1ll*A.len*B.len<=(A.len+B.len)*30ll){ for (int i=0;i<A.len;i++) for (int j=0;j<B.len;j++) t3[i+j]=(t3[i+j]+1ll*A.f[i]*B.f[j])%mod; cpy(A.f,t3,len);clr(t3,len); }else { cpy(t1,A.f,A.len); cpy(t2,B.f,B.len); int n=1; while(n<len)n<<=1; NTT(t1,1,n);NTT(t2,1,n); px(t1,t2,n);NTT(t1,0,n); cpy(A.f,t1,len); clr(t1,n);clr(t2,n); }return (Poly){len,A.f}; } int n,m,k; int main() { scanf("%d%d%d",&m,&n,&k); Init(n); for (int i=1;i<=m;i++){ scanf("%d",&a[i].len); a[i].f=tbuf; for (int j=1;j<=a[i].len;j++) a[i].f[j]=C(a[i].len-1,j-1)*ifac[j]%mod; tbuf+=++a[i].len; } while(m>1){ for (int i=2;i<=m;i+=2) a[i/2]=times(a[i-1],a[i]); if (m&1)a[m/2+1]=a[m]; m=(m+1)/2; } ll ans=0; for (int i=k;i<n;i++){ if ((i-k)&1)ans=(ans-C(i,k)*a[1].f[n-i]%mod*fac[n-i])%mod; else ans=(ans+C(i,k)*a[1].f[n-i]%mod*fac[n-i])%mod; }printf("%lld",(ans+mod)%mod); return 0; } ```