Ynoi2019模拟赛

Ynoi2019模拟赛

前言

太毒瘤了!!!
感觉都是经典的问题,但以前从没想过有什么更优的办法。。
果然是我太菜了吗。。。
出题人lxl的题解
lxl的题解已经很详细了,我就直接贴代码吧。。

Yuno loves sqrt technology I

链接

P5046 Yuno loves sqrt technology I

吐槽

第一遍写完之后果不其然被卡成20分。
看了下洛谷的题解感觉有些常数应该比我做法大的方法都过了,感觉不可思议,贴了一个题解的代码发现也被卡成20.。
怀疑洛谷的测评姬变慢了。。好多题解的代码都过不了。。
然后只能自己卡常,交了5页测评。。。还好最后还是过了。。

\(Code\)

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;
inline int Read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
inline LL read(){
    LL x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
inline void print(LL x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
const int B=520;
const int T=193;
int n,m;
int a[N],bl[N],pos[N],t[N];
int pre[T+5][B+5],suf[T+5][B+5],c[T+5][B+5],sz[T+5];
int s[T+5][N];
inline void add(int x,int w){while(x<=n){t[x]+=w;x+=x&-x;} }
inline int get(int x){int re=0;while(x){re+=t[x];x-=x&-x;} return re;}
LL F[T+5][T+5];
int main(){
    n=Read();m=Read();
    for(register int i=1;i<=n;++i) {
        a[i]=Read();
        bl[i]=(i+B-1)/B;
        c[bl[i]][sz[bl[i]]++]=a[i];
        pos[a[i]]=i;
    }
    LL l,r;
    int x,y,z;
    for(register int i=1;i<=bl[n];++i){
        sort(c[i],c[i]+sz[i]);
        l=(i-1)*B+1;
        r=min(i*B,n);
        for(register int j=l,k=1;j<=r;++j,++k){
            add(a[j],1);
            pre[i][k]=k-get(a[j])+pre[i][k-1];
        }
        for(register int j=l,k=1;j<=r;++j,++k) add(a[j],-1);
        for(register int j=r,k=1;j>=l;--j,++k){
            suf[i][k]=get(a[j])+suf[i][k-1];
            add(a[j],1);
        }
        for(register int j=r,k=1;j>=l;--j,++k) add(a[j],-1);
    }
    for(register int i=1;i<bl[n];++i){
        int k=0;
        for(register int j=1;j<=n;++j){
            while(c[i][k]<j&&k<sz[i]) ++k;
            if(bl[pos[j]]<i)s[i][pos[j]]=k;
            else if(bl[pos[j]]>i) s[i][pos[j]]=B-k;
        }
        for(register int j=1;j<=n;j+=4) {
            s[i][j]+=s[i][j-1];
            s[i][j+1]+=s[i][j];
            s[i][j+2]+=s[i][j+1];
            s[i][j+3]+=s[i][j+2];
        }
    }
    for(register int i=1;i<bl[n];++i){
        for(register int j=i+1;j<bl[n];++j){
            F[i][j]=s[j][j*B]-s[j][(i-1)*B]+F[i][j-1];
        }
    }
    LL ans=0;int itl,itr;
    for(register int tt=1;tt<=m;++tt){
        l=read();r=read();
        l^=ans;r^=ans;
        if(bl[l]==bl[r]){
            x=bl[l];y=0;
            ans=pre[x][r-(x-1)*B]-pre[x][l-1-(x-1)*B];
            for(register int i=0;i<sz[x];++i){
                if(pos[c[x][i]]<l) ans-=y;
                else if(pos[c[x][i]]<=r) ++y;
            }
        }
        else{
            y=0;x=bl[l];z=bl[r];
            ans=suf[x][x*B-l+1]+pre[z][r-(z-1)*B]+F[x+1][z-1];
            itl=x*B;itr=(z-1)*B;
            for(register int i=x+1;i<z;++i)
                ans+=pre[i][B]+s[i][itl]-s[i][l-1]+s[i][r]-s[i][itr];
            for(itl=0,itr=0;itl<sz[x];++itl){
                for(;itr<sz[z]&&c[x][itl]>c[z][itr];++itr) if(pos[c[z][itr]]<=r) ++y;
                if(pos[c[x][itl]]>=l) ans+=y;
            }
        }
        print(ans);puts("");
    }
    return 0;
}

Yuno loves sqrt technology II

链接

P5047 Yuno loves sqrt technology II

吐槽

做法类似第十四分块,二次离线时要用根号平衡。。
for比while更快,然而写莫队不用while就非常蛋疼。。。
卡常过程比第一题更熟练了,只交了两页测评。。

\(Code\)

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+10;

int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void print(LL x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int B;
int n,m,cnt;
int a[N],b[N],g[N],h[N];
int find(int x){
    int l=1,r=cnt,mid;
    while(1){
        mid=l+r>>1;
        if(b[mid]==x) return mid;
        else if(b[mid]<x) l=mid+1;
        else r=mid-1;
    }
}
struct query{
    int l,r,id;
}q[N];
struct node{
    int l,r,f,id,op;
};
vector<node> p[N];
bool cmpq(query x,query y){
    return g[x.l]!=g[y.l]?g[x.l]<g[y.l]:x.r<y.r;
}
int xiao[N],da[N],t[N];
inline void add(int x){
    for(;x<=n;x+=x&-x)++t[x];
}
inline int get(int x){
    int re=0;
    for(;x;x-=x&-x) re+=t[x];
    return re;
}
LL ans[N];
int main(){
    n=read();m=read();B=sqrt(n);
    for(register int i=1;i<=n;++i){
        a[i]=read();
        b[i]=a[i];
        g[i]=(i+B-1)/B;
    }
    sort(b+1,b+1+n);
    cnt=1;
    for(register int i=2;i<=n;++i) 
        if(b[i]!=b[i-1]) b[++cnt]=b[i];
    for(register int i=1;i<=n;++i) a[i]=find(a[i]);
    for(register int i=1;i<=n;++i){
        add(a[i]);
        xiao[i]=get(a[i]-1);
        da[i]=i-get(a[i]);
    }
    for(register int i=1;i<=n;++i) t[i]=0;
    for(register int i=1;i<=m;++i){
        q[i].l=read();q[i].r=read();
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmpq);
    int l=1,r=0;
    for(register int i=1;i<=m;++i){
        //++r f(x,[l,r])=f(x,[1,r])-f(x,[1,l-1])
        if(r<q[i].r) p[l-1].push_back((node){r+1,q[i].r,-1,q[i].id,2});
        for(;r<q[i].r;++r) ans[q[i].id]+=da[r+1];
        //--l
        if(l>q[i].l) p[r].push_back((node){q[i].l,l-1,1,q[i].id,1});
        for(;l>q[i].l;--l) ans[q[i].id]-=xiao[l-1];
        //--r;
        if(r>q[i].r) p[l-1].push_back((node){q[i].r+1,r,1,q[i].id,2});
        for(;r>q[i].r;--r)ans[q[i].id]-=da[r];
        //++l
        if(l<q[i].l) p[r].push_back((node){l,q[i].l-1,-1,q[i].id,1});
        for(;l<q[i].l;++l)ans[q[i].id]+=xiao[l];
    }
    int v,id;
    for(register int i=1;i<=n;++i){
        xiao[i]=(a[i]-1)/B+1;
        da[i]=a[i]/B+1;
    }
    for(register int i=1;i<=n;++i){
        v=(a[i]/B);
        for(register int k=1;k<=v;++k) ++h[k];
        v=v*B+1;
        for(;v<=a[i];++v) ++t[v];
        for(register int j=0;j<p[i].size();++j){
            id=p[i][j].id;
            if(p[i][j].op==1){
                if(p[i][j].f==1) {
                    ans[id]+=(LL)i*(p[i][j].r-p[i][j].l+1);
                    for(register int o=p[i][j].l;o<=p[i][j].r;++o)
                        ans[id]-=t[a[o]]+h[xiao[o]];
                }
                else{
                    ans[id]-=(LL)i*(p[i][j].r-p[i][j].l+1);
                    for(register int o=p[i][j].l;o<=p[i][j].r;++o)
                        ans[id]+=t[a[o]]+h[xiao[o]];
                }
            }
            else{
                if(p[i][j].f==1) {
                    for(register int o=p[i][j].l;o<=p[i][j].r;++o)
                        ans[id]+=t[a[o]+1]+h[da[o]];
                }
                else{
                    for(register int o=p[i][j].l;o<=p[i][j].r;++o)
                        ans[id]-=h[da[o]]+t[a[o]+1];
                }
            }
        }
    }
    for(register int i=1;i<=m;++i) ans[q[i].id]+=ans[q[i-1].id];
    for(register int i=1;i<=m;++i){
        print(ans[i]);puts("");
    }
    return 0;
}

Yuno loves sqrt technology III

链接

P5048 Yuno loves sqrt technology III

吐槽

我以前也写过区间众数,前面部分想法是相同的。。
但以前在处理两边 \(O(n^{0.5})\) 大小的小块时,是直接用线段树来算区间内出现次数的。。
这题这个把问题转化为是否存在出现 \(ans+1\) 次元素,就不需要真的算出一个元素的出现次数。。
感觉自己还是太菜了。。只能膜拜想出这种做法的神仙。。
实现上感觉这是三题里最不卡常的,一发就过了~

\(Code\)

#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=5e5+10;

int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void print(int x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n,m,B,cnt;
int a[N],b[N],g[N],c[N],L[N],R[N];
int find(int x){
    int l=1,r=cnt,mid;
    while(1){
        mid=l+r>>1;
        if(b[mid]==x) return mid;
        else if(b[mid]<x) l=mid+1;
        else r=mid-1;
    }
}
int F[2010][2010];
int pos[N];
vector<int> v[N];
int main(){
    n=read();m=read();B=sqrt(n);
    for(int i=1;i<=n;++i) {
        a[i]=read();
        b[i]=a[i];
        g[i]=(i+B-1)/B;
    }
    for(int i=1;i<=g[n];++i){
        L[i]=(i-1)*B+1;
        R[i]=min(i*B,n);
    }
    sort(b+1,b+1+n);
    cnt=1;
    for(register int i=2;i<=n;++i) 
        if(b[i]!=b[i-1]) b[++cnt]=b[i];
    for(register int i=1;i<=n;++i) a[i]=find(a[i]);
    int mx;
    for(int i=1;i<g[n];++i){
        mx=0;
        for(int j=i;j<g[n];++j){
            for(int k=L[j];k<=R[j];++k){
                ++c[a[k]];
                if(c[a[k]]>mx) mx=c[a[k]];
            }
            F[i][j]=mx;
        }
        for(int j=i;j<g[n];++j)
            for(int k=L[j];k<=R[j];++k)
                --c[a[k]];
    }
    for(int i=1;i<=n;++i){
        pos[i]=c[a[i]];
        ++c[a[i]];
        v[a[i]].push_back(i);
    }
    int ans=0,l,r;
    for(int tt=1;tt<=m;++tt){
        l=read()^ans;r=read()^ans;
        ans=F[g[l]+1][g[r]-1];
        for(int i=l;i<=R[g[l]];++i){
            for(;pos[i]+ans<v[a[i]].size();++ans)
                if(v[a[i]][pos[i]+ans]>r) break;
        }
        for(int i=L[g[r]];i<=r;++i){
            for(;pos[i]-ans>=0;++ans)
                if(v[a[i]][pos[i]-ans]<l) break;
        }
        print(ans);puts("");
    }
    return 0;
}
posted @ 2020-08-24 19:57  Iscream-2001  阅读(82)  评论(0编辑  收藏  举报
/* */