In mathematics you don't understand things, you just get used to them.

Description

Link.

给定一个数列 $\sf a_1,a_2,....a_n$,请求出下面这个结果在模 $\sf 998244353$ 下的答案。

$$ \sum_{i=1}^{n}\sum_{j=1}^{n}2^{a_i a_j} $$

Solution

这题涉及一个 trick:$\sf ij=\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2}$,是 UQ 里面 EI 给我讲的,说明一下。

首先我们令 $\sf c_{a_{i}}=the~number~of~the~occurrences~of~a_{i},mx=\max\{a_{i}\}$。

然后来推式子:

$$ \begin{aligned} \sf\sum_{i=1}^{n}\sum_{j=1}^{n}2^{a_{i}a_{j}}&=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}2^{ij} \\ &=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}2^{\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2}} \\ &=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}2^{\binom{i+j}{2}}2^{-\binom{i}{2}}2^{-\binom{j}{2}} \\ &=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}2^{\binom{i+j}{2}}2^{-\binom{i}{2}}2^{-\binom{j}{2}} \\ \end{aligned}\\ $$

现在我们令 $\sf t_{i}=2^{\binom{i}{2}},it_{i}=2^{-\binom{i}{2}}$。

那么 $\sf i+j$ 那项你就直接拿出来最后单独算即可。

$$ \begin{aligned} \sf\sum_{i=1}^{n}\sum_{j=1}^{n}2^{a_{i}a_{j}} &=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}2^{\binom{i+j}{2}}2^{-\binom{i}{2}}2^{-\binom{j}{2}} \\ &=\sf\sum_{i=1}^{mx}\sum_{j=1}^{mx}c_{i}c_{j}t_{i+j}it_{i}it_{j} \\ \end{aligned}\\ $$

最后直接算:

$$ \sf \sum_{i=1}^{mx}\sum_{j=0}^{mx-1}c_{i}it_{i}c_{i-j}it_{i-j} $$

卷积 完了。

记住模数非质的时候不一定有逆元啊啊啊啊!!!!

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD=998244353;
void exGCD(LL one,LL ano,LL &x,LL &y)
{
    if(ano==0)    x=1,y=0;
    else    exGCD(ano,one%ano,y,x),y-=(one/ano)*x;
}
LL getInv(LL val,LL _MOD){LL res,w; exGCD(val,_MOD,res,w); return (res%_MOD+_MOD)%_MOD;}
LL fspow(LL bas,LL fur)
{
    LL res=1;
    while(fur)
    {
        if(fur&1)    res=LL(res)*bas%MOD;
        bas=LL(bas)*bas%MOD;
        fur>>=1;
    }
    return (res+MOD)%MOD;
}
LL fac[200010],ifac[200010];
//LL binom(LL n,LL k){return n>=k?LL(fac[n])*ifac[k]%(MOD-1)*ifac[n-k]%(MOD-1):0;}
LL binom(LL n,LL k){return n>=k?LL(n)*(n-1)/2%(MOD-1):0;}
namespace Poly
{
    typedef vector<LL> poly;
    #define len(x) (LL((x).size()))
    LL lim,rev[800010];
    void ntt(poly &f,LL op)
    {
        for(LL i=0;i<lim;++i)    if(i<rev[i])    swap(f[i],f[rev[i]]);
        for(LL len=2;len<=lim;len<<=1)
        {
            LL bas=fspow(op==1?3:332748118,(MOD-1)/len);
            for(LL fr=0;fr<lim;fr+=len)
            {
                LL now=1;
                for(LL ba=fr;ba<fr+(len>>1);++ba,now=LL(now)*bas%MOD)
                {
                    LL tmp=LL(now)*f[ba+(len>>1)]%MOD;
                    f[ba+(len>>1)]=(f[ba]-tmp+MOD)%MOD;
                    f[ba]=(f[ba]+tmp)%MOD;
                }
            }
        }
        if(op==-1)
        {
            LL tmp=getInv(lim,MOD);
            for(LL i=0;i<lim;++i)    f[i]=LL(f[i])*tmp%MOD;
        }
    }
    poly operator*(poly f,poly g)
    {
        LL n=len(f)+len(g)-1; lim=1;
        while(lim<n)    lim<<=1;
        f.resize(lim),g.resize(lim);
        for(LL i=0;i<lim;++i)    rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
        ntt(f,1),ntt(g,1);
        for(LL i=0;i<lim;++i)    f[i]=LL(f[i])*g[i]%MOD;
        ntt(f,-1),f.resize(n);
        return f;
    }
}using namespace Poly;
LL n,mx,c[100010],t[100010],it[100010],ans,ex[200010];
int main()
{
    poly f;
    scanf("%lld",&n);
    for(LL i=1,x;i<=n;++i)    scanf("%lld",&x),mx=max(mx,x),++c[x];
    f.resize(mx+1);
    fac[0]=1;
    for(LL i=1;i<=(mx<<1);++i)    fac[i]=LL(fac[i-1])*i%(MOD-1);
//    for(LL i=0;i<=(mx<<1);++i)    ifac[i]=getInv(fac[i],MOD-1);
//    printf("%lld\n",getInv(fac[2],MOD));
//    printf("(%lld %lld %lld %lld)\n",fac[2],ifac[2],ifac[0],binom(2,2));
    for(LL i=0;i<=mx;++i)    t[i]=fspow(2,binom(i,2));
    for(LL i=0;i<=mx;++i)    it[i]=getInv(t[i],MOD);
//    for(LL i=1;i<=mx;++i)    printf("%lld ",fac[i]); puts("");
//    for(LL i=1;i<=mx;++i)    printf("%lld ",binom(i,2)); puts("");
//    for(LL i=1;i<=mx;++i)    printf("%lld ",LL(i)*(i-1)/2%MOD); puts("");
    for(LL i=0;i<=mx;++i)    f[i]=LL(c[i])*it[i]%MOD;
    for(LL i=1;i<=(mx<<1);++i)    ex[i]=fspow(2,binom(i,2));
    f=f*f;
    for(LL i=0;i<len(f);++i)    ans=(ans+LL(f[i])*ex[i]%MOD)%MOD;
    printf("%lld\n",ans);
    return 0;
}

maths combinatorics polynomials

Solution -「POJ 1322」Chocolate
上一篇 «
Solution -「CF 1491H」Yuezheng Ling and Dynamic Tree
» 下一篇