CF1205E Expected Value Again (border性质+莫比乌斯反演)

· · 题解

算法一

### 算法二 - 一个字符串 $s$ 有长度为 $i$ 的 border 就有长度为 $|s|−i$ 的 period(一个字符串 $s$ 有长度为 $l$ 的 period 当且仅当对于所有的 $1\le i\le |s|−l$ 都有 $s_i=s_{i+l}$),于是把 border 个数转为求 period 个数 - 首先转化一下问题:$f(s)^2$ 相当于枚举两个 $1\le i,j<n$,使得 $s$ 同时存在 $i,j$ 两个 period,于是可以考虑算出每一对 $1≤i,j<n$ 的贡献后加起来 - 现在考虑对于一对 $i,j$,有多少个长度为 $n$ 的字符串 $s$ 满足 $s$ 同时存在 $i,j$ 两个 period - 这相当于 $n$ 个点,在编号差为 $i$ 或 $j$ 的点对之间连边表示这两个下标上的字符相等,计算出连通块个数为 $cnt$,则这对 $i,j$ 的贡献为 $k^{cnt}

算法三

一个结论:cnt=\max(\gcd(i,j),i+j-n)

证明:(以下假设 i\le j

那么答案即为 ans\times k^n=\sum\limits_{i=1}^{n-1}\sum\limits_{j=1}^{n-1}k^{\max(\gcd(i,j),i+j-n)}

算法四

枚举 i+j\gcd(i,j),算对应的 (i,j) 的个数。

\begin{aligned} &\sum_{s=2}^{2n-2}\sum_{g=1}^{n-1}\sum_{i=\max(1,s-n+1)}^{\min(n-1,s-1)}[\gcd(i,s-i)=g]\\ =&\sum_{s=2}^{2n-2}\sum_{g|s}\sum_{i=\max(1,\frac{s}{g}-\lfloor\frac{n-1}{g}\rfloor)}^{\min(\lfloor\frac{n-1}{g}\rfloor,\frac{s}{g}-1)}[\gcd(i,\frac{s}{g}-i)=1]\\ \end{aligned}

l=\max(1,\frac{s}{g}-\lfloor\frac{n-1}{g}\rfloor),r=\min(\lfloor\frac{n-1}{g}\rfloor,\frac{s}{g}-1)

\begin{aligned} &\sum_{s=2}^{2n-2}\sum_{g|s}\sum_{i=l}^{r}[\gcd(i,\frac{s}{g}-i)=1]\\ =&\sum_{s=2}^{2n-2}\sum_{g|s}\sum_{d|\frac{s}{g}}\mu(d)\sum_{i=l}^{r}[d|i]\\ =&\sum_{s=2}^{2n-2}\sum_{g|s}\sum_{d|\frac{s}{g}}\mu(d)\left(\left\lfloor\frac{r}{d}\right\rfloor-\left\lfloor\frac{l-1}{d}\right\rfloor\right) \end{aligned}

复杂度 O(n\log^2n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace FGF
{
    int n,m;
    const int N=2e5+5,mo=1e9+7;
    int vis[N],mu[N],p[N],cnt,pw[N],ans;
    vector<int> g[N];
    int inv(int x)
    {
        int s=1,y=mo-2;
        while(y)
        {
            if(y&1)s=1ll*s*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return s;
    }
    void init()
    {
        mu[1]=1,pw[0]=1,pw[1]=m;
        for(int i=2;i<=2*n;i++)
        {
            pw[i]=1ll*pw[i-1]*m%mo;
            if(!vis[i])p[++cnt]=i,mu[i]=-1;
            for(int j=1;j<=cnt&&p[j]*i<=2*n;j++)
            {
                vis[p[j]*i]=1;
                if(i%p[j]==0)break;
                mu[p[j]*i]=-mu[i];
            }
        }
        for(int i=1;i<=2*n;i++)
            for(int j=i;j<=2*n;j+=i)
                g[j].push_back(i);
    }
    int calc(int x,int y)
    {
        if(y<=0||x<=1)return 0;
        int l=max(1,x-y),r=min(y,x-1),sum=0;
        if(l>r)return 0;
        for(int i=0;i<g[x].size();i++)
            sum=(sum+mu[g[x][i]]*(r/g[x][i]-(l-1)/g[x][i])%mo)%mo;
        return (sum+mo)%mo;
    }
    void work()
    {
        scanf("%d%d",&n,&m);
        init();
        for(int s=2;s<=2*n-2;s++)
            for(int i=0;i<g[s].size();i++)
                ans=(ans+1ll*calc(s/g[s][i],(n-1)/g[s][i])*pw[max(s-n,g[s][i])]%mo)%mo;
        printf("%lld",1ll*ans*inv(pw[n])%mo);
    }
}
int main()
{
    FGF::work();
    return 0;
}

算法五

考虑容斥。先假设所有 (i,j) 均取 i+j-n,那么此时贡献为

\sum\limits_{i=1}^{n-1}\sum\limits_{j=1}^{n-1}k^{i+j-n}

枚举 i+j ,计算一下其出现次数即可。预处理 k 的幂,可做到 O(n)

然后修正答案

\begin{aligned} &\sum_{p=1}^{n-1}\sum_{i=1}^{n-1}\sum_{j=1}^{n-1}[\gcd(i,j)=p][i+j-n<p](k^p-k^{i+j-n})\\= &\sum_{p=1}^{n-1}\sum_{i=1}^{\lfloor\frac{n-1}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{p}\rfloor}[\gcd(i,j)=1][(i+j)p-n<p](k^p-k^{(i+j)p-n})\\= &\sum_{p=1}^{n-1}\sum_{i=1}^{\lfloor\frac{n-1}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{p}\rfloor}\sum_{d|i,d|j}\mu(d)[(i+j)p-n<p](k^p-k^{(i+j)p-n})\\= &\sum_{p=1}^{n-1}\sum_{d=1}^{\lfloor\frac{n-1}{p}\rfloor}\mu(d)\sum_{i=1}^{\lfloor\frac{n-1}{dp}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{dp}\rfloor}[(i+j)dp-n<p](k^p-k^{(i+j)dp-n})\\= &\sum_{T=1}^{n-1}\sum_{d|T}\mu(\frac{T}{d})\sum_{i=1}^{\lfloor\frac{n-1}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{T}\rfloor}[(i+j)T-n<d](k^d-k^{(i+j)T-n}) & \end{aligned}

拆成两部分分别算

\sum_{T=1}^{n-1}\sum_{d|T}\mu(\frac{T}{d})\sum_{i=1}^{\lfloor\frac{n-1}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{T}\rfloor}k^{(i+j)T-n}[(i+j)T-n<d]

先把 k^{-n} 提出来。后面部分可以看作一个关于 k^T 的多项式。

\because(i+j)T-n<d\\ \therefore i+j\le\lfloor\frac{d+n-1}{T}\rfloor\\ \because d\le T\\ \therefore i+j\le\lfloor\frac{d+n-1}{T}\rfloor\le\lfloor\frac{n-1}{T}\rfloor+1

相当于枚举一个 x=i+j\ (xT\le 2n-2,x\le\lfloor\frac{d+n-1}{T}\rfloor),每个这样的 x 会出现 x-1 次,因此把答案多项式的 xT 项减去 (x-1)\mu(\frac{T}{d})。具体实现时枚举 T,然后用一个数组存储这个 T 导致的答案多项式的变化量,其中第 x 个位置对应答案多项式的第 xT 项。枚举 d 时对这个数组打上标记,然后枚举完 d 后按标记算出变化量即可。这样处理后,这部分的后半部分可以 O(1) 算。

\sum_{T=1}^{n-1}\sum_{d|T}\mu(\frac{T}{d})\sum_{i=1}^{\lfloor\frac{n-1}{T}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{T}\rfloor}[(i+j)T-n<d]k^d

对于 x=i+j\le\lfloor\frac{n-1}{T}\rfloor+1,每个这样的 x 会出现 x-1 次,故这个式子后半部分的值为 \sum_{x=2}^{\lfloor\frac{n-1}{T}\rfloor+1}(x-1)k^d=\lfloor\frac{n-1}{T}\rfloor\times(\lfloor\frac{n-1}{T}\rfloor-1)k^d

所以原式的后半部分均可以 O(1) 算,总复杂度为枚举 T,dO(n\log n)

(这个式子太阴间了于是有了算法六)

算法六

\begin{aligned}&\sum_{p=1}^{n-1}\sum_{i=1}^{n-1}\sum_{j=1}^{n-1}[\gcd(i,j)=p][i+j-n<p](k^p-k^{i+j-n})\\ =&\sum_{p=1}^{n-1}\sum_{i=1}^{\lfloor\frac{n-1}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{p}\rfloor}[\gcd(i,j)=1][(i+j)p-n<p](k^p-k^{(i+j)p-n})\\ =&\sum_{p=1}^{n-1}\sum_{i=1}^{\lfloor\frac{n-1}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n-1}{p}\rfloor}[\gcd(i,j)=1][(i+j)\le\lfloor\frac{n-1}{p}\rfloor+1](k^p-k^{(i+j)p-n})\\ =&\sum_{p=1}^{n-1}\sum_{s=2}^{\lfloor\frac{n-1}{p}\rfloor+1}\sum_{i=1}^{s-1}[\gcd(i,s-i)=1](k^p-k^{sp-n})\\ =&\sum_{p=1}^{n-1}\sum_{s=2}^{\lfloor\frac{n-1}{p}\rfloor+1}\sum_{i=1}^{s-1}[\gcd(i,s)=1](k^p-k^{sp-n})\\ \end{aligned}

前半部分

\begin{aligned} &\sum_{p=1}^{n-1}\sum_{s=1}^{\lfloor\frac{n-1}{p}\rfloor+1}\sum_{i=1}^{s-1}[\gcd(i,s)=1]k^p\\= &\sum_{p=1}^{n-1}\sum_{s=2}^{\lfloor\frac{n-1}{p}\rfloor+1}\phi(s)k^p\\ \end{aligned}

预处理一下 \phi 的前缀和即可 O(n) 算。

后半部分

\begin{aligned} \sum_{p=1}^{n-1}\sum_{s=2}^{\lfloor\frac{n-1}{p}\rfloor+1}\phi(s)k^{sp-n} \end{aligned}

我们在算 \sum\limits_{i=1}^{n-1}\sum\limits_{j=1}^{n-1}k^{i+j-n} 的时候只考虑 i+j-n>0 的情况,则这里也只需要考虑 i+j-n>0 的情况。如果 sp-n>0,那么 sp>np\nmid ns\ge \lfloor\frac{n-1}{p}\rfloor+1,上式就可以变为 \sum_{p=1}^{n-1}\phi(\lfloor\frac{n-1}{p}\rfloor+1)k^{(\lfloor\frac{n-1}{p}\rfloor+1)p-n},可以 O(n) 算;p|ns>\frac{n}{p}=\lfloor\frac{n-1}{p}\rfloor+1,此时 s 不存在,如果按上式算的话会贡献到 (\lfloor\frac{n-1}{p}\rfloor+1)p-n=0 次项上,又因为最后统计答案的时候不会统计 0 次项,所以对答案没有影响,详见代码。

总复杂度 O(n)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace FGF
{
    int n,m;
    const int N=2e5+5,mo=1e9+7;
    int p[N],phi[N],s[N],cnt,ans,c[N]; 
    int qpow(int x,int y)
    {
        int s=1;
        while(y)
        {
            if(y&1)s=1ll*s*x%mo;
            x=1ll*x*x%mo;
            y>>=1;
        }
        return s;
    }
    void init()
    {
        phi[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(!phi[i])p[++cnt]=i,phi[i]=i-1;
            for(int j=1;j<=cnt&&p[j]*i<=n;j++)
            {
                if(i%p[j]==0){phi[i*p[j]]=phi[i]*p[j];break;}
                phi[i*p[j]]=phi[i]*(p[j]-1);
            }
        }
    } 
    void work()
    {
        scanf("%d%d",&n,&m); 
        init();
        for(int i=2;i<=n;i++)
            s[i]=(s[i-1]+phi[i])%mo;
        for(int i=1;i<n-1;i++)
            c[i]=n-i-1;
        for(int i=1,d;i<n;i++)
            d=(n-1)/i,c[i]=(c[i]+s[d+1])%mo,c[(d+1)*i-n]=(c[(d+1)*i-n]-phi[d+1]+mo)%mo;
        for(int i=1,k=m;i<n;i++,k=1ll*k*m%mo)
            ans=(ans+1ll*c[i]*k%mo)%mo;
        printf("%lld",1ll*ans*qpow(m,mo-1-n)%mo);
    }
}
int main()
{
    FGF::work();
    return 0;
}