HDU 5321 Beautiful Set(莫比乌斯反演+数论)

大致题意:告诉你两个人计算美丽数字的方法。对于ZSTU来说,先把几何看作序列,每个序列的美丽数字是这个序列所有子区间的gcd之和,每个集合的美丽数字是这个集合所有排列序列的美丽数字之和。对于HDU来说,在集合中挑选k个数字,这k个数字的美丽数字是他们的gcd*k,这个集合的美丽数字是k的所有取值和所有挑选方法的美丽数字之和。现在让你分别在mod的意义下计算两个人的美丽数字之和,问最后在mod的意义下哪一个更大。


对于ZSTU来说,这个问题还是比较棘手的。首先,我肯定是要计算每一个gcd的贡献,不可能去枚举 n! 种集合的表示方法。当gcd为x的时候,我们考虑定义 \large f(k,x) 表示从所有元素种取k个且这k个数字的gcd是x的方案数。然后再去考虑排列顺序,把这k个元素内部捆绑,有k!种方式,然后外面与其他数字形成n-k+1个部分,一个全排列(n-k+1)!,那么最后的答案就是,其中的cnt[x]表示集合种x的倍数的个数:

                            \large ZSTU=\sum_{x=1}^{max}\sum_{k=1}^{cnt[x]}x*f(k,x)*k!*(n-k+1)!

现在我们来考虑这个\large f(k,x)。我们不妨设 \large g(k,x) 表示从所有元素种选择k个且它们的gcd是x的倍数的方案数。显然,g和f是有关系的,有 \large g(k,x)=\sum_{x|d}^{max}f(k,d),然后我们可以推出g的公式: \large g(k,x)=C_{cnt[x]}^{k}。那么,我们就可以进行莫比乌斯反演了。根据反演公式有:

                            \large f(k,x)=\sum_{x|d}^{max}\mu(\frac{d}{x})*g(k,d)=\sum_{x|d}^{max}\mu(\frac{d}{x})*C_{cnt[d]}^{k}

答案可以写成:  \large ZSTU=\sum_{k=1}^{cnt[d]}k!*(n-k+1)!*\sum_{x=1}^{max}\sum_{x|d}^{max}x*\mu(\frac{d}{x})*C_{cnt[d]}^{k}

交换求和次序:  \large ZSTU=\sum_{k=1}^{cnt[d]}k!*(n-k+1)!*\sum_{d=1}^{max}C_{cnt[d]}^{k}*\sum_{x|d}^{max}x*\mu(\frac{d}{x})

注意到最后一项 \sum_{x|d}^{max}x*\mu(\frac{d}{x})只与d相关,所以可以考虑预处理,对于每一个d只需要枚举所有因子,计算求和即可。可以在O(N\sqrt{N})时间复杂度内完成预处理,我们不妨令h(d)=\sum_{x|d}^{max}x*\mu(\frac{d}{x})。那么答案可以写成:

                           \large ZSTU=\sum_{k=1}^{cnt[d]}k!*(n-k+1)!*\sum_{d=1}^{max}C_{cnt[d]}^{k}*h(d)

把组合数展开:  \large ZSTU=\sum_{d=1}^{max}cnt[d]!*h(d)*\sum_{k=1}^{cnt[d]}\frac{(n-k+1)!}{(cnt[d]-k)!}

还是一样注意到右边的式子,我们可以单独考虑。我们不妨设b(d)表示右边那个和式。这里我就不一一赘述,转载一个大神的博客内容,他的P(x)就对应我的b(d):

按照他所说的方法进行化简,可以得到:  \large B(d)=\frac{(n+1)!}{(cnt[d]-1)!*(n-cnt[d]+2)},那么对于ZSTU来说,最后的结果就是:

                                     \large ZSTU=\sum_{d=1}^{max}cnt[d]!*h(d)*b(d)

 


然后我们来考虑HDU怎么算。HDU是计算所有的取K个数字的方案对应的gcd*k之和。同样的,我们还是得按照gcd计算贡献。这里一些函数的定义与计算ZSTU的时候一样,不再赘述。可以得到,HDU的结果为:

                                   \large HDU=\sum_{k=1}^{cnt[x]}\sum_{x=1}^{max}f(k,x)*k*x

相对来说比较容易理解和计算,还是一样的,我们对f进行莫比乌斯反演,借助辅助函数g,这里就省略过程直接代入:

                                  \large HDU=\sum_{k=1}^{cnt[d]}k*\sum_{x=1}^{max}\sum_{x|d}^{max}C_{cnt[d]}^{k}*x*\mu(\frac{d}{x})

和ZSTU一样的交换求和次序,然后用h(d)替换右边:

                                  \large HDU=\sum_{d=1}^{max}h(d)*\sum_{k=1}^{cnt[d]}k*C_{cnt[d]}^{k}

对于右边的式子,我们把和式展开,然后首尾相加(组合数首尾相同),我们发现它等于\large cnt[d]*2^{cnt[d]-1},那么HDU的答案就可以写成:

                                  \large HDU=\sum_{d=1}^{max}h(d)*cnt[d]*2^{cnt[d]-1}

 


到这里,我们总算是大功告成啦……比较一下两个的大小即可。

总结一下,就是需要预处理阶乘、逆元、阶乘逆元、二的幂、h(d)和b(d)以及cnt[d]。把这些求完之后,我们就可以O(N)的求HDU和ZSTU的值。然后预处理的过程求h(d)是O(N\sqrt{N}),求cnt[d]是O(N\log N),其余的用线性方法都是O(N)的,那么总的复杂度就是O(N\sqrt{N}+T*N\log N)这里面忽略了线性的初始化和每一次回答问题。具体见代码:

#include<bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define mod 258280327
#define LL long long
#define N 100010
using namespace std;

int ifac[N],fac[N],inv[N],mu[N],p[N],pw[N];
int n,m,h[N],num[N],cnt[N],b[N];
bool isp[N];

void init()
{
    int sz=0;
    isp[1]=mu[1]=pw[0]=1;
    for(int i=2;i<N;i++)
    {
        if(!isp[i])p[++sz]=i,mu[i]=-1;
        for(int j=1;j<=sz&&i*p[j]<N;j++)
        {
            isp[i*p[j]]=1;
            if(i%p[j]==0){mu[p[j]*i]=0;break;}
                    else mu[p[j]*i]=-mu[i];
        }
    }
    pw[1]=2;
    fac[0]=inv[0]=ifac[0]=1;
    fac[1]=inv[1]=ifac[1]=1;
    for(int i=2;i<N;i++)
    {
        pw[i]=pw[i-1]*2LL%mod;
        fac[i]=fac[i-1]*(LL)i%mod;
        inv[i]=(mod-mod/i)*(LL)inv[mod%i]%mod;
        ifac[i]=ifac[i-1]*(LL)inv[i]%mod;
    }
}

void get_h()
{
    for(int i=1;i<N;i++)
        for(int j=1;j*j<=i;j++)
        {
            if (i%j) continue;
            h[i]+=j*mu[i/j];
            if (j*j!=i) h[i]+=i/j*mu[j];
        }
}

int main()
{
    // file(g);
    IO; init(); get_h();
    while(cin>>n)
    {
        for(int i=1;i<=m;i++)
            num[i]=cnt[i]=0;m=0;
        for(int i=1;i<=n;i++)
        {
            int x; cin>>x;
            m=max(m,x);num[x]++;
        }
        for(int i=1;i<=m;i++)
            for(int j=i;j<=m;j+=i)
                cnt[i]+=num[j];
        for(int i=1;i<=n;i++)
            b[i]=fac[n+1]*(LL)ifac[i-1]%mod*inv[n-i+2]%mod;
        int ZSTU=0,HDU=0;
        for(int i=1;i<=m;i++)
        {
            if (!cnt[i]) continue;
            HDU+=cnt[i]*(LL)pw[cnt[i]-1]%mod*h[i]%mod;
            ZSTU+=h[i]*(LL)fac[cnt[i]]%mod*b[cnt[i]]%mod;
            if (ZSTU>=mod) ZSTU-=mod;
            if (HDU>=mod) HDU-=mod;
        }
        if (ZSTU==HDU) cout<<"Equal "<<HDU<<endl;
        if (HDU>ZSTU) cout<<"Mr. Hdu "<<HDU<<endl;
        if (ZSTU>HDU) cout<<"Mr. Zstu "<<ZSTU<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u013534123/article/details/81390010