题解:P14009 「florr IO Round 1」数字游戏

题目链接

随机跳题跳到的。虽有“两道题拼在一起”之嫌,但任然不失为一道好题。

看到这个定义,毫无疑问需要莫比乌斯反演,简单推一下式子。

\[\begin{align*} f(l,r) &=\sum^{a_l}_{b_1=1}\sum^{a_{l+1}}_{b_2=1}\sum^{a_{l+2}}_{b_3=1}\dots\sum^{a_{r}}_{b_{r-l+1}=1} [\gcd(b_1,b_2,b_3,\dots,b_{r-l+1})=1] \\ &= \sum^{a_l}_{b_1=1}\sum^{a_{l+1}}_{b_2=1}\sum^{a_{l+2}}_{b_3=1}\dots\sum^{a_{r}}_{b_{r-l+1}=1} \sum_{ d \mid \gcd(b_1,b_2,b_3,\dots,b_{r-l+1})} \mu (d) \\ &= \sum _{d=1} ^ {\max \{ a_l,a_{l+1},\cdots,a_{r} \}} \mu(d)\sum^{a_l}_{b_1=1} [d \mid b_1] \sum^{a_{l+1}}_{b_2=1} [d \mid b_2] \sum^{a_{l+2}}_{b_3=1} [d \mid b_3 ]\dots\sum^{a_{r}}_{b_{r-l+1}=1} [d \mid b_{r-l+1}] \\ &= \sum_{d=1}^{\max \{ a_l,a_{l+1},\cdots,a_{r} \} } \mu (d) \prod _{i=l}^r \left \lfloor \frac{a_i}{d} \right \rfloor \end{align*} \]

全局和(不妨令 \(V= \max \{a_1,a_2,\cdots,a_n \}\)

\[\begin{align*} \sum _{l=1} ^n \sum _{r=l} ^n f(l,r) &= \sum _{l=1} ^ n \sum _{r=l} ^ n \sum _{d=1} ^ {\max \{ a_l,a_{l+1},\cdots,a_{r} \} } \mu (d) \prod _{i=l} ^ r \left \lfloor \frac{a_i}{d} \right \rfloor \\ &= \sum _{d=1} ^ V \mu(d) \sum _{l=1} ^n \sum _{r=l} ^n \prod _{i=l} ^r \left \lfloor \frac{a_i}{d} \right \rfloor\\ \end{align*} \]

该式子最后一项的

\[\sum _{l=1} ^n \sum _{r=l} ^n \prod _{i=l} ^r \left \lfloor \frac{a_i}{d} \right \rfloor \]

不好继续展开,考虑直接用数据结构维护。

这样我们扫描 \(d\),依次修改当 \(d\) 变化是会变化的 \(\left \lfloor \frac{a_i}{d}\right\rfloor\)。我们得到 \(\mathcal O(n \sqrt V)\) 次单点修改,\(\mathcal O(V)\) 次查询全局和。

维护结点 \([\mathrm{ans},\mathrm{pre},\mathrm{suf},\mathrm{prod}]\),其中 \(\mathrm{ans}\) 表示该区间答案 \(\displaystyle \sum _{i=l}^r \sum _{j=i} ^r \prod _{k=i} ^j \left \lfloor \frac{a_k}{d}\right\rfloor\)\(\mathrm{pre}\) 表示前缀积之和 \(\displaystyle \sum _{i=l} ^r \prod _{k=l} ^i \left \lfloor \frac{a_k}{d}\right\rfloor\)\(\mathrm{suf}\) 表示是区间后缀积之和 \(\displaystyle \sum_{i=l} ^r \prod _{k=i} ^r \left \lfloor \frac{a_k}{d}\right\rfloor\)\(\mathrm{prod}\) 表示区间积 \(\prod _{k=l} ^r \left \lfloor \frac{a_k}{d}\right\rfloor\)。合并两个区间为

\[[\mathrm{ans}_l,\mathrm{pre}_l,\mathrm{suf}_l,\mathrm{prod}_l] \oplus [\mathrm{ans}_r,\mathrm{pre}_r,\mathrm{suf}_r,\mathrm{prod}_r]\\=[\mathrm{ans}_l+\mathrm{ans}_r+\mathrm{suf}_l\times \mathrm{pre}_r,\mathrm{suf} _l \times \mathrm{prod} _r +\mathrm {suf} _r,\\\mathrm{pre} _l + \mathrm{prod} _l \times \mathrm{pre}_r,\mathrm{prod} _l \times \mathrm{prod} _r] \]

简单分析一下可以知道,单位元为 \([0,0,0,1]\)。单独元素 \(x=\left \lfloor \frac{a_i}{d}\right\rfloor\) 构成 \([x,x,x,x]\)。满足结合律,不满足交换律,构成半群。

由于不满足交换律,似乎只能用线段树做到 \(\mathcal O(n \sqrt V \log n)\)。试了分块,没成功。求助得到 lxl 认为不可做

考虑继续发掘题目性质。一点比较显然的是在 \(d\)\(1\) 变化 \(\sqrt V\) 时有很多修改,几乎整棵线段树上每个结点都被修改了,这样的话如果能够“共用”从根到叶子的路径上的点可以大大降低复杂度了。而 \(d\)\(\sqrt V\)\(V\) 这一段修改相对“稀疏”。

所以我就有了如下的想法,每个结点额外维护 \(\mathrm{nxt}\) 表示该节点中下一次修改的 \(d\),如果递归到的结点 \(\mathrm{xnt}\) 比修改的 \(d\) 大就退出,否则直接暴力递归左右子树修改。大致写出这样的代码(其中的 w 直接表示 \([\mathrm{ans},\mathrm{pre},\mathrm{suf},\mathrm{prod}]\)):

inline void push_up(int p){
    tr[p].nxt=min(tr[lc].nxt,tr[rc].nxt);
    tr[p].w=tr[lc].w+tr[rc].w;
}
void upd(int p,int pl,int pr,int id){
    if(tr[p].nxt>id) return;
    if(pl==pr){
        tr[p].w=answer(a[pl]/id);
        if(a[pl]/id==0) tr[p].nxt=V+1;
        else tr[p].nxt=a[pl]/(a[pl]/id)+1;
        return;
    }
    assert(tr[p].nxt==id);
    int mid=(pl+pr)>>1;
    upd(lc,pl,mid,id);
    upd(rc,mid+1,pr,id);
    push_up(p);
}

乍一看复杂度任然是 \(\mathcal O (n \sqrt V \log n)\) 的,但仔细一想复杂度严格低于取 \(B\) 来平衡的官解(\(\le B\)\(\gt B\) 的部分均为严格优,\(\le B\) 的部分会有一些无需重构的结点在此处被优化,\(\gt B\) 的部分会共用一部分结点)。

则复杂度在 \(\mathcal O(n \sqrt V)\)\(\mathcal O(n \sqrt {V \log n})\) 之间,能否证到低于根号半 \(\log\) 的复杂度,我不大清楚。而且目前是最优解。

最后放一下完整的代码

#include <bits/stdc++.h>
using namespace std;
const int N=7e4+10;
const unsigned mod=998244353;
inline void addmod(unsigned &x,unsigned y){x+=y;(x>=mod)&&(x-=mod);}
inline void submod(unsigned &x,unsigned y){addmod(x,mod-y);}
inline unsigned plsmod(unsigned x,unsigned y){addmod(x,y);return x;}
inline unsigned minmod(unsigned x,unsigned y){return plsmod(x,mod-y);}
inline unsigned mulmod(unsigned x,unsigned y){return 1ull*x*y%mod;};
unsigned mu[N];
namespace Seive{
bool vis[N];
int pr[N/4];
void euler(){
    int cnt=0;
    for(int i=2;i<N;i++){
        if(!vis[i]){
            pr[++cnt]=i;
            mu[i]=mod-1;
        }
        for(int j=1;pr[j]*i<N;j++){
            vis[i*pr[j]]=1;
            if(i%pr[j]==0){
                mu[i*pr[j]]=0;
                break;
            }else{
                mu[i*pr[j]]=mulmod(mu[i],mu[pr[j]]);
            }
        }
    }
    mu[1]=1;
}
}
int a[N];
unsigned ans;
vector<int> ds[N];
int n,V;
struct answer{
    unsigned ans,suf,pre,prod;
    answer():ans(0),suf(0),pre(0),prod(1){}
    answer(int _a):ans(_a),suf(_a),pre(_a),prod(_a){}
    answer(int _a,int _s,int _p,int _pp):ans(_a),suf(_s),pre(_p),prod(_pp){}
    answer operator+(const answer o){
        answer res;
        res.ans=plsmod(ans,o.ans);
        addmod(res.ans,mulmod(suf,o.pre));
        res.suf=plsmod(mulmod(suf,o.prod),o.suf);
        res.pre=plsmod(pre,mulmod(prod,o.pre));
        res.prod=mulmod(prod,o.prod);
        return res;
    }
};
struct node{
    answer w;
    int nxt;//下一个需要修改的时刻
}tr[N*4];
#define lc (p<<1)
#define rc (p<<1|1)
inline void push_up(int p){
    tr[p].nxt=min(tr[lc].nxt,tr[rc].nxt);
    tr[p].w=tr[lc].w+tr[rc].w;
}
void build(int p,int pl,int pr){
    if(pl==pr){
        tr[p].w=answer(a[pl]);
        tr[p].nxt=2;
        return;
    }
    int mid=(pl+pr)>>1;
    build(lc,pl,mid);
    build(rc,mid+1,pr);
    push_up(p);
}
void upd(int p,int pl,int pr,int id){
    if(tr[p].nxt>id) return;
    if(pl==pr){
        tr[p].w=answer(a[pl]/id);
        if(a[pl]/id==0) tr[p].nxt=V+1;
        else tr[p].nxt=a[pl]/(a[pl]/id)+1;
        return;
    }
    assert(tr[p].nxt==id);
    int mid=(pl+pr)>>1;
    upd(lc,pl,mid,id);
    upd(rc,mid+1,pr,id);
    push_up(p);
}
int main(){
    Seive::euler();
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        V=max(V,a[i]);
    }
    build(1,1,n);
    addmod(ans,tr[1].w.ans);
    for(int d=2;d<=V;d++){
        upd(1,1,n,d);
        addmod(ans,mulmod(mu[d],tr[1].w.ans));
    }
    printf("%u\n",ans);
    return 0;
}
posted @ 2026-04-07 21:42  MZMTab  阅读(17)  评论(0)    收藏  举报