「Codeforces 1644F」Basis

好久没写 blog 了,来水一篇(

Description

有两种对于数组的操作:

  • \(F(a,k)\):将 \(a\) 数组的每个数重复写 \(k\) 次,然后截取前 \(|a|\) 个元素作为变换后的数组。
  • \(G(a,x,y)\):将 \(a\) 数组中的每个 \(x\) 替换成 \(y\)\(y\) 替换成 \(x\)

先要求构造 \(m\) 个长度为 \(n\) 的数组 \(s_1\sim s_m\),每个数都 \(\in[1,k]\),满足对于任意一个长度为 \(n\) 且每个数都 \(\in[1,k]\) 的数组,都能由某个 \(s_i\) 经过若干次 \(F\)\(G\) 得到。

\(m_{\min} \bmod 998244353\)\(1\leq n,k\leq 2\times 10^5\)

Solution

首先特判掉 \(n=1\)\(k=1\) 的情况。

假如只有 \(G\) 操作,相当于把 \(n\) 个数划分成若干个集合,每个集合中的数相同,故 \(m_{\min}=\sum_{i=1}^k\begin{Bmatrix}n\\i\end{Bmatrix}\)

形如 a...a|b...b|c...c|d...d\(s_i\),根据 \(F\) 操作,只需保留 abcd,所以 \(s_i\) 可以省略掉。具体地,如果 \(s_i\)\(j\) 个分一段(允许最后一段不满),每一段内部的数都相同,则 \(s_i\) 可以省略。

直接枚举 \(j\) 来减掉 \(j\) 的贡献会算重,考虑容斥。

记符合条件的 \(j_{\max}=x\),则会在 \(j\mid x\)\(j\) 的方案数中被算到,并且 \(s_i\) 会对 \(m_{\min}\) 贡献 \([x=1]\)。注意到 \(\sum_{d\mid x}\mu(d)=[x=1]\),所以容斥系数就是 \(\mu\)

枚举 \(j\),每 \(j\) 个分一段,钦定每一段都相同,这样就可以忽略 \(F\) 操作了,再把计算结果乘上 \(\mu(j)\) 的系数贡献给 \(m_{\min}\)。故 \(m_{\min}=\sum_{j=1}^{\infty}\mu(j)\sum_{i=1}^k\begin{Bmatrix}\lceil\frac n j\rceil\\i\end{Bmatrix}\)(因为允许最后一段不满,所以 \(j\) 枚举到 \(\infty\))。后面的 \(\sum\) 就是求一行斯特林数的前缀和。

处理 \(j\) 枚举到 \(\infty\):当 \(j>n\) 时后面的 \(\sum=1\)\(\lceil\frac n j\rceil=1\),当 \(i=1\) 时才有贡献),\(\sum_{j=0}^{\infty}\mu(j)=0\)(每个质因子,如果选,对 \(\mu\) 贡献 \(-1\),不选贡献 \(1\)\(1+(-1)=0\) 的若干次还是 \(0\)),故 \(m_{\min}=\sum_{j=1}^{n}\sum_{i=1}^k\begin{Bmatrix}\lceil\frac n j\rceil\\i\end{Bmatrix}+(\sum_{j=0}^{\infty}\mu(j)-\sum_{j=0}^n \mu(j))=\sum_{j=1}^{n}\sum_{i=1}^k\begin{Bmatrix}\lceil\frac n j\rceil\\i\end{Bmatrix}-\sum_{j=0}^n \mu(j)\)

求一行第二类斯特林数前缀和第 \(k\) 项的方法(不用 NTT):通项公式 \(\begin{Bmatrix}n\\k\end{Bmatrix}=\dfrac{1}{k!}\displaystyle\sum\limits_{i=0}^k (-1)^{k-i}i^n \dbinom{k}{i}=\sum_{i=0}^k\frac{(-1)^{k-i}}{(k-i)!}\times \frac{i^n}{i!}\),令 \(a_i=\large\frac{(-1)^i}{i!}\normalsize,b_i=\large\frac{i^n}{i!}\normalsize\),正常来说是对 \(a,b\) 求个卷积。\(\sum_{x=1}^k\sum_{i=0}^x a_ib_{x-i}=\sum_{i=0}^k a_i \sum_{x=i}^k b_{x-i}=\sum_{i=0}^k a_i\sum_{j=0}^{k-i}b_j\),对 \(b\) 求一遍前缀和即可,这样可以直接暴力卷(因为只要求第 \(k\) 项)。

因为 \(\lceil\frac{n}{j}\rceil\) 的总量只有 \(\mathcal O(n\log n)\),所以可以通过本题。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,mod=998244353;
int n,k,cnt,p[N],mu[N],vis[N],fac[N],inv[N],a[N],b[N],ans;
int qpow(int x,int n){
    int ans=1;
    for(;n;n>>=1,x=1ll*x*x%mod)
        if(n&1) ans=1ll*ans*x%mod;
    return ans;
}
int S2(int n,int k){
    int sum=0;
    k=min(n,k);
    for(int i=0;i<=k;i++) b[i]=((i?b[i-1]:0)+1ll*qpow(i,n)*inv[i]%mod)%mod;
    for(int i=0;i<=k;i++) sum=(sum+1ll*a[i]*b[k-i]%mod)%mod;
    return sum;
} 
signed main(){
    scanf("%d%d",&n,&k);
    if(n==1||k==1) puts("1"),exit(0);
    mu[1]=fac[0]=inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
    for(int i=2;i<=n;i++){
        if(!vis[i]) p[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&i*p[j]<=n;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
            mu[i*p[j]]=-mu[i];
        }
    }
    for(int i=1;i<=n;i++)
        fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
    for(int i=0;i<=n;i++) a[i]=1ll*(i&1?mod-1:1)*inv[i]%mod;
    for(int i=1;i<=n;i++)
        if(mu[i]) ans=(ans+1ll*S2(n/i+(n%i!=0),k)*mu[i])%mod;
    for(int i=0;i<=n;i++) ans-=mu[i];
    printf("%d\n",(ans+mod)%mod);
    return 0;
}
posted @ 2022-04-08 16:12  maoyiting  阅读(105)  评论(0编辑  收藏  举报