• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Recommended Posts

a

观察能构成合法区间的条件就是奇数成对,同时每对奇数之间没有\(0\)

使用一类线段树维护历史信息的手段来解决本题,为了规避麻烦的标记下放,可以将每个"偶数个奇数"的出现区间左右端点刻画出来并使用\(r-l 1\)来计算

同时在每个节点要支持\(01\) 翻转的部分维护"对未翻转时奇数/偶数"的权值增加量方便下方

代码显示常数int N=5e5 10

int n,Q,a[N],his[N],ans[N];

vectorpairint,int qu[N];

布尔班[N],od[N];

#定义ls p1

#定义rs p1|1

#定义埃尔松p1,l,mid

#定义rson p1|1,mid 1,r

波尔rev[N2];

int num[N2][2],delt[N2][2],sum[N2];

inline void push_up(int p){

sum[p]=sum[ls]sum[RS];

数字[p][0]=数字[ls][0]数字[rs][0].

数字[p][1]=数字[ls][1]数字[rs][1].

返回;

}

内嵌void push _ rev(int p){rev[p]^=1;swap(num[p][0],num[p][1]);}

inline void push_add(int p,int v,int fl){

delt[p][rev[p]^fl]=五世;

sum[p]=num[p][fl]* v;

返回;

}

inline void push_down(int p){

for(int I=0;I2;i) if(delt[p])

push_add(ls,delt[p],I);

push_add(rs,delt[p],I);

delt[p]=0;

}

if(rev[p]){

push _ rev(ls);push _ rev(RS);

rev[p]=0;

}

返回;

}

inline void upd(int R,int v,int fl,int p=1,int l=1,int r=n){

如果(r=R)返回push_add(p,v,fl),void();

int mid=(l r)1;push _ down(p);

if(Rmid) upd(R,v,fl,rson);

更新(天主教、天主教、佛罗里达州、埃尔松);

return push _ up(p);

}

inline int query(int st,int ed,int p=1,int l=1,int r=n){

if(st=lr=ed)返回sum[p];

int mid=(l r)1,RES=0;push _ down(p);

if(edmid) res=query(st,ed,rson);

if(st=mid) res=query(st,ed,埃尔松);

返回表示留数

}

inline void dfs(int p,int l,int r){

如果(!数字[p][1])返回;

if(l==r){

delt[p][0]=delt[p][1]=0;

数字[p][0]=数字[p][1]=0;

返回;

}

int mid=(l r)1;push _ down(p);

外勤支助部(埃尔松);外勤支助部(外勤支助司);

return push _ up(p);

}

inline void Reverse(int R,int p=1,int l=1,int r=n){

如果(r=R)返回push _ rev(p);

int mid=(l r)1;push _ down(p);

if(Rmid) Reverse(R,rson);

反向(R,埃尔松);

return push _ up(p);

}

inline void build(int p,int l,int r){

if(l==r){

num[p][0]=1;

sum[p]=-l;

返回;

}

int mid=(l r)1;

build(lson); build(rson); return push_up(p); } inline void output(int p,int l,int r){ if(l==r) return cout<<sum[p]<<" ",void(); int mid=(l+r)>>1; push_down(p); output(lson); output(rson); return ; } #undef ls #undef rs #undef lson #undef rson signed main(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); n=read(); Q=read(); for(int i=1;i<=n;++i) a=read(); for(int i=1;i<=Q;++i){ int l=read(),r=read(); qu[r].emplace_back(l,i); } build(1,1,n); for(int i=1;i<=n;++i){ if(!a&&i) dfs(1,1,n); if(a&1){ upd(i,i,0); upd(i,-i,1); Reverse(i); } for(auto t:qu){ upd(i,i+1,0); ans[t.sec]+=query(t.fir,i); upd(i,-1-i,0); } } rep(i,1,Q) print(ans); return 0; }

b

对于 \(Q\) 个属于 \([1,m]\) 的 随机区间,将左端点排序后,对应的右端点最长上升子序列长度是 \(\Theta(\sqrt Q)\) 级别的

那么将所有询问分成 \(\dfrac{Q}{\sqrt Q}\) 组,每组中询问形成嵌套关系,使用势能线段树暴力扩展即可

但是据说会被卡常,所以代码写了个能过的暴力

Code Display
const int N=15010;
int n,m,Q,sum[N<<2];
struct operation{
    int l,r,v,id;
}opt[N<<1];
inline void upd(int p,int l,int r,int st,int ed){
    if(sum[p]==r-l+1) return ;
    if(st<=l&&r<=ed) return sum[p]=r-l+1,void();
    int mid=(l+r)>>1;
    if(st<=mid) upd(p<<1,l,mid,st,ed);
    if(ed>mid) upd(p<<1|1,mid+1,r,st,ed);
    sum[p]=sum[p<<1]+sum[p<<1|1];
    return ;
}
inline void build(int p,int l,int r){
    sum[p]=0; if(l==r) return ;
    int mid=(l+r)>>1;
    build(p<<1,l,mid); build(p<<1|1,mid+1,r);
}
signed main(){
    freopen("b.in","r",stdin); freopen("b.out","w",stdout);
    n=read(); m=read(); Q=read();
    for(int i=1;i<=n;++i) opt[i]={i,i,read(),0};
    int cnt=n;
    for(int i=1;i<=m;++i){
        int l=read(),r=read(),v=read();
        opt[++cnt]={l,r,v,i};
    }
    sort(opt+1,opt+cnt+1,[&](const operation A,const operation B){return A.v<B.v;});
    while(Q--){
        int l1=read(),r1=read(),l2=read(),r2=read();
        int lst=0;
        int ans=0;
        int siz=r2-l2+1;
        build(1,1,siz);
        for(int i=1;i<=cnt;++i){
            if(opt[i].id&&(opt[i].id<l1||opt[i].id>r1)) continue;
            if(opt[i].r<l2||opt[i].l>r2) continue;
            upd(1,1,siz,max(opt[i].l,l2)-l2+1,min(opt[i].r,r2)-l2+1);
            ans+=(sum[1]-lst)*opt[i].v;
            if(sum[1]==siz) break;   
            lst=sum[1];
        }
        print(ans);
    }
    return 0;
}

c

发现本质上要完成的工作是对 \(n\times K\) 个点值做背包,但是每个元素的值域只有 \(\pm1\) ,也就是在 \(n\) 个数字里面找到 \(m\) 个并将它们乘起来再对所有选择方案的权值求和

设有 \(x\) 个元素贡献 \(1\) 而 \(n-x\) 个元素贡献 \(-1\),对于所有 \(x\) 求出来 \([z^m](1-z)^{n-x}(1+z)^{x}\)

而这通过分配幂次变成 \(\displaystyle \sum_{i=0}^m(-1)^{m-i}\binom{n-x}{m-i}\binom{x}i\)

再拆成阶乘逆元可以通过一次卷积进行计算

在对 \(a_i\) 形成的桶做 \(\rm FWT\) 后得到的点值解方程可以得到上面所写的 \(x\),那么直接代换成背包后的结果再做逆变换得到答案

Code Display
const int N=2e5+10;
int n,m,K;
inline void FWT(vector<int> &f,int lim){
    for(int p=2;p<=lim;p<<=1){
        int len=p>>1;
        for(int k=0;k<lim;k+=p) for(int l=k;l<k+len;++l){
            int x=f[l],y=f[l+len];
            f[l+len]=x-y;
            f[l]=x+y;
        }
    }
    return ;
}
inline void iFWT(vector<int> &f,int lim){
    for(int p=2;p<=lim;p<<=1){
        int len=p>>1;
        for(int k=0;k<lim;k+=p) for(int l=k;l<k+len;++l){
            int x=f[l],y=f[l+len];
            f[l+len]=del(x,y);
            f[l]=add(x,y);
        }
    }
    for(int tmp=ksm(lim,mod-2),i=0;i<lim;++i) ckmul(f[i],tmp);
    return ;
}
int W[1<<20],r[1<<20];
inline void NTT(vector<int> &f,int lim,int opt){
    f.resize(lim);
    for(int i=0;i<lim;++i){
        r[i]=r[i>>1]>>1|((i&1)?(lim>>1):0);
        if(i<r[i]) swap(f[i],f[r[i]]);
    }
    for(int p=2;p<=lim;p<<=1){
        int len=p>>1; W[0]=1; 
        W[1]=ksm(3,(mod-1)/p);
        if(opt==-1) W[1]=ksm(W[1],mod-2);
        for(int j=2;j<len;++j) W[j]=mul(W[j-1],W[1]);
        for(int k=0;k<lim;k+=p){
            for(int l=k;l<k+len;++l){
                int tt=mul(f[l+len],W[l-k]);
                f[l+len]=del(f[l],tt);
                ckadd(f[l],tt);
            }
        }        
    }
    if(opt==-1) for(int tmp=ksm(lim,mod-2),i=0;i<lim;++i) ckmul(f[i],tmp);
}
int ifac[N],fac[N];
signed main(){
    freopen("c.in","r",stdin); freopen("c.out","w",stdout);
    n=read(); m=read(); K=read();
    vector<int> f,g,a(K);
    for(int i=1;i<=n;++i) a[read()]++;
    if(m==1){
        rep(i,0,K-1) print(a[i]);
        putchar('\n');
        exit(0);
    }
    fac[0]=1;
    for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
    ifac[n]=ksm(fac[n],mod-2);
    for(int i=n;i>=1;--i) ifac[i-1]=mul(ifac[i],i);
    
    FWT(a,K);
    int lim=1;
    while(lim<=n) lim<<=1;
    f.resize(m+1);
    g.resize(n-m+1);
    for(int i=0;i<=m;++i){
        f[i]=mul(ifac[i],ifac[m-i]);
        if((m-i)&1) f[i]=del(0,f[i]);
    }
    for(int i=0;i<=n-m;++i) g[i]=mul(ifac[i],ifac[n-m-i]);
    NTT(f,lim,1); NTT(g,lim,1);
    for(int i=0;i<lim;++i) ckmul(f[i],g[i]);
    NTT(f,lim,-1);
    for(int i=0;i<=n;++i) ckmul(f[i],mul(fac[i],fac[n-i]));
    for(int i=0;i<K;++i) a[i]=f[(n-a[i])/2];
    iFWT(a,K);
    for(int i=0;i<K;++i) print(a[i]); putchar('\n');
    return 0;
}

Link to comment
Share on other sites