QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: NuclearPasta

Posted at: 2026-04-08 17:48:37

Last updated: 2026-04-08 17:51:05

Back to Problem

New Editorial for Problem #17398

题意

给定 $n,q(n\le 10 ^ 7,q\le 10^6)$,对一个初始为空集的集合 $S$ 做如下操作:给定一个 $x(1 \le x \le n)$,若集合中含 $x$ 则删除,不含就加入,每次操作后问对于所有可能 $m \ge 2,k$,集合中能表示成 $ms + k$ 的数有多少个?

关于答案的特性

首先通过取 $m = 2$ 的同时 $k$ 在 $0$ 或者 $1$ 中任选,可以得到一个超过 $\frac{|S|}{2}$ 的答案,而且总有最优解在 $m$ 为质数时取到,这样就可以处理单次询问,但是难点其实在多次询问,注意到当修改次数不大于 $\frac{|S|}{4}$ 时答案所包含的元素中至少有 $\frac{3|S|}{8}$ 个点是原集合中保留的元素,这样就可以将单组询问的做法推广到多组询问的均摊做法。

分组处理

考虑当集合大小不大于 $3$ 的时候特判,否则对所有元素每 $6$ 个一组,每组每一对求出差的所有质因数,其中集合元素用链表处理,质因数考虑在线性筛时求出每个数的最小质因子和彻底除去这个质因子得到的数,可以得到一个高度为 $\omega(n)$ 的有根数,每次记录最小质因子并跳到完全去除后的结果即可。

这样下来我们根据前面的结论得出当一个质数被这轮操作记录为 $\frac{3|S|}{16}$ 时这个质数才有可能是取到答案的 $m$,枚举这样的质数,离线维护本询问和后续操作的元素对应的余数分布,维护的操作规模 $\frac{|S|}{4}$,我们枚举到 $\frac{5|S|}{2}$ 个对,至多在后续操作中枚举 $\frac{40}{3}\omega(n)$ 个质数,最终得到 $n + q\omega(n)$ 的做法。

最后要注意的是,虽然时空限制比较友好,但毕竟 $n,q$ 比正常的大,请加上快读并且慎用 stl :: vector

#include<bits/stdc++.h>
using namespace std;
const int N = 10000009,Q = 1000009,PR = 700009;
int n,q,prv[N],nxt[N],a[Q],cnt,fcnt[Q],fmx,ans[Q]; 
int prcnt,pr[PR],prid[N];
int beg = 0,ed = 0;
bool npr[N],exi[N];
int dft[PR],minpr[N],to[N];
bool dst[PR];
int dat[5009],dlt[3 * Q],cntdat,cntdlt;
int s[N];
void add_list(int x) {
    exi[x] = true;
    cnt ++;
    prv[x] = ed;
    nxt[ed] = (ed > 0) * x;
    beg = (beg == 0) ? x : beg;
    ed = x;
}
void del_list(int x){ 
    exi[x] = false;
    cnt --;
    if(ed == x)
        ed = prv[x];
    if(beg == x)
        beg = nxt[x];
    if(prv[x])
        nxt[prv[x]] = nxt[x];
    if(nxt[x])
        prv[nxt[x]] = prv[x];
    nxt[x] = prv[x] = 0;
} 
int gcd(int x,int y){
    return y == 0 ? x : gcd(y,x % y);
}
#define fadd(x) \
    if(!dft[prid[x]])\
        dlt[++cntdlt] = x;\
    dft[prid[x]] ++;
namespace IO{
    char ibuf[99967],*ip1 = ibuf,*ip2 = ibuf;
    char gc(){
        return (ip1 == ip2) && (ip2 = (ip1 = ibuf) + fread(ibuf,1,99967,stdin),ip1 == ip2) ? EOF : *ip1++;
    } 
    void fstin(int &x){
        x = 0;
        char c = gc();
        while(!isdigit(c))
            c = gc();
        while(isdigit(c))
            x = (x << 1) + (x << 3) + c - '0',c = gc(); 
    }
    char wbuf[99967],*wp1 = wbuf,*wp2 = wbuf + 99967;
    inline void pc(const char c){
        if(wp1 == wp2){
            fwrite(wbuf,1,99967,stdout);
            wp1 = wbuf;
        }
        *wp1 ++ = c;
    }
    void write(int x){
        if(x > 9)
            write(x / 10);
        pc((x % 10) ^ 48);
    }
};
using namespace IO;
int main(){
//    #ifndef LOCAL
    //    freopen("h.in","r",stdin);
    //    freopen("h.out","w",stdout);
    //#endif
    fstin(n),fstin(q);
//    cerr << n << ' ' << q << '\n';
    npr[0] = true,npr[1] = true;
    for(int i = 2; i <= n; i ++){
        if(!npr[i]){
            pr[++prcnt] = i;
            minpr[i] = i;
            prid[i] = prcnt;
            to[i] = 1;
        }
        for(int j = 1; j <= prcnt && i * pr[j] <= n; j ++){
            npr[i * pr[j]] = true;
            minpr[i * pr[j]] = pr[j];
            to[i * pr[j]] = i;
            if(minpr[i * pr[j]] == minpr[i]){
                to[i * pr[j]] = to[i];
                break; 
            }
        }
    }
//    cerr << prcnt;
//    return 0;
//    return 0;
    for(int i = 1; i <= q; i ++){
        fstin(a[i]);
    }
//    return 0;
    for(int i = 1; i <= q; i ++){
        //assert(prv[0] == 0);
        //assert(nxt[0] == 0);
        //cout << i << endl;
        if(exi[a[i]]){
            del_list(a[i]);
        }
        else{
            add_list(a[i]);
        }
        //if(cnt > 0){
    ///        for(int fi = beg; fi != 0; fi = nxt[fi])
    //            pc(' '),write(fi),pc('\n'),assert(!ntp[fi]),assert(exi[fi]),exi.reset(fi),ntp.set(fi);
    //        for(int fi = beg; fi != 0; fi = nxt[fi])
    //            exi.set(fi),ntp.reset(fi);
    //    }
        if(cnt == 0){
            pc('0'),pc('\n');
        }
        else if(cnt == 1){
            pc('1'),pc('\n');
        }
        else if(cnt == 2){
            pc(49 + (abs(beg - ed) != 1)),pc('\n');
        }
        else if(cnt == 3){
            pc(50 + (gcd(abs(beg - ed),abs(ed - prv[ed])) != 1)),pc('\n');
        }
        else{
            for(int fi = beg; fi != 0; ){
                int a1 = 0,a2 = 0,a3 = 0,a4 = 0,a5 = 0,a6 = 0;
                a1 = fi;
                fi = nxt[fi];
                if(fi){
                    a2 = fi,fi = nxt[fi];
                    int o = abs(a2 - a1);
                    while(o > 1){
                        fadd(minpr[o])
                        o = to[o];
                    }
                    if(fi){
                        a3 = fi,fi = nxt[fi];
                        o = abs(a3 - a1);
                        while(o > 1){
                            fadd(minpr[o])
                            o = to[o];
                        }
                //        cerr << "3-1\n";
                        o = abs(a2 - a3);
                        while(o > 1){
                            fadd(minpr[o])
                            o = to[o];
                        }
                        if(fi){
                            a4 = fi,fi = nxt[fi];
                            o = abs(a4 - a1);
                            while(o > 1){
                                fadd(minpr[o])
                                o = to[o];
                            }
                    //        cerr << "4-1";
                            o = abs(a4 - a2);
                            while(o > 1){
                                fadd(minpr[o])
                                o = to[o];
                            }
                    //        cerr << "4-2";
                            o = abs(a4 - a3);
                            while(o > 1){
                                fadd(minpr[o])
                                o = to[o];
                            }
                            if(fi){
                                a5 = fi, fi = nxt[fi];
                                o = abs(a5 - a1);
                                while(o > 1){
                                    fadd(minpr[o])
                                    o = to[o];
                                }
                        //        cerr << "5-1";
                                o = abs(a5 - a2);
                                while(o > 1){
                                    fadd(minpr[o])
                                    o = to[o];
                                }
                        //        cerr << "5-2";
                                o = abs(a5 - a3);
                                while(o > 1){
                                    fadd(minpr[o])
                                    o = to[o];
                                }
                    //            cerr << "5-3";
                                o = abs(a5 - a4);
                                while(o > 1){
                                    fadd(minpr[o])
                                    o = to[o];
                                }
                                if(fi){
                                    a6 = fi,fi = nxt[fi];
                                    o = abs(a6 - a1);
                                    while(o > 1){
                                        fadd(minpr[o])
                                        o = to[o];
                                    }
                    //                cerr << "6-1";
                                    o = abs(a6 - a2);
                                    while(o > 1){
                                        fadd(minpr[o])
                                        o = to[o];
                                    }
                    //                cerr << "6-2";
                                    o = abs(a6 - a3);
                                    while(o > 1){
                                        fadd(minpr[o])
                                        o = to[o];
                                    }
                        //            cerr << "6-3";
                                    o = abs(a6 - a4);
                                    while(o > 1){
                                        fadd(minpr[o])
                                        o = to[o];
                                    }
                        //            cerr << "6-4";
                                    o = abs(a6 - a5);
                                    while(o > 1){
                                        fadd(minpr[o])
                                        o = to[o];
                                    }
                                }
                            }
                        }
                    }
                }
            }
            for(int fi = 1; fi <= cntdlt; fi ++){
                if(dft[prid[dlt[fi]]] >= cnt * 3 / 16){
                    dst[prid[dlt[fi]]] = true;
                    dat[++cntdat] = dlt[fi];
                }
                dft[prid[dlt[fi]]] = 0;
            }
            cntdlt = 0;
            int step = min(q - i,cnt / 4);
            for(int fi = 1; fi <= cntdat; fi ++){
                int p = dat[fi];
                fcnt[0] = 0x3f3f3f3f;
                for(int j = beg; j != 0; j = nxt[j]){
                //    write(j),pc(' '),write(j % p),pc(' '),write(s[j % p]),pc(' '),write(fmx),pc('\n');
                    fcnt[s[j % p]] --;
                    s[j % p] ++;
                    fcnt[s[j % p]] ++;
                    if(fcnt[fmx + 1] > 0)
                        fmx ++;
                }
            //    write(p),pc(' '),write(fmx),pc('\n');
                ans[i] = max(ans[i],fmx);
                for(int j = i + 1; j <= i + step; j ++){
                    if(exi[a[j]]){
                        exi[a[j]] = false;
                        fcnt[s[a[j] % p]] --;
                        s[a[j] % p] -- ;
                        fcnt[s[a[j] % p]] ++;
                        if(fcnt[fmx] == 0)
                            fmx --;
                    }
                    else{
                        exi[a[j]] = true;
                        fcnt[s[a[j] % p]] --;
                        s[a[j] % p] ++;
                        fcnt[s[a[j] % p]] ++;
                        if(fcnt[fmx + 1] > 0)
                            fmx ++;
                    }
                    ans[j] = max(ans[j],fmx);
                }
                for(int j = i + step; j > i; j --){
                    if(exi[a[j]]){
                        exi[a[j]] = false;
                        fcnt[s[a[j] % p]] --;
                        s[a[j] % p] -- ;
                        fcnt[s[a[j] % p]] ++;
                        if(fcnt[fmx] == 0)
                            fmx --;
                    }
                    else{
                        exi[a[j]] = true;
                        fcnt[s[a[j] % p]] --;
                        s[a[j] % p] ++;
                        fcnt[s[a[j] % p]] ++;
                        if(fcnt[fmx + 1] > 0)
                            fmx ++;
                    }
                }
                for(int j = beg; j != 0; j = nxt[j]){
                    fcnt[s[j % p]] --;
                    s[j % p] --;
                    fcnt[s[j % p]] ++;
                    if(fcnt[fmx] == 0)
                        fmx --;
                }
            //    write(fcnt[0] == 0x3f3f3f3f),pc('\n');
            }
            for(int fi = 1; fi <= cntdat; fi ++){
                dst[prid[dat[fi]]] = false;
            }
            fmx = 0;
            cntdat = 0;
            write(ans[i]);
            pc('\n');
            for(int fi = i + 1; fi <= i + step; fi ++){
                if(exi[a[fi]])
                    del_list(a[fi]);
                else
                    add_list(a[fi]);
                write(ans[fi]);
                pc('\n');
            }
            i = i + step;
            //cerr << "end\n";
        }
    }
    fwrite(wbuf,1,wp1 - wbuf,stdout);
    return 0;
}

Comments

No comments yet.