zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    第六周总结
    第五周总结
    第四周总结
    7-1 抓老鼠啊~亏了还是赚了?
    春季学期第八周作业
    春季学期第七周作业
    春季学期第六周作业
    春季学期第五周作业
    春季学期第四周作业
    春季学期第三周作业
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/13555947.html
Copyright © 2011-2022 走看看