• 【考试总结】20220711


    客蒜计题

    本题计算的是三角形个数而不是直角三角形个数

    强制 \(a\le b\le c\) 并枚举 \(c\) 再把算式 \(\Theta(1)\) 处理即可

    Code Display
    inline int S(int l,int r){
    	return (r-l+1)%mod*((l+r)%mod)%mod*inv2%mod;
    }
    signed main(){
    	freopen("cilrag.in","r",stdin);
    	freopen("cilrag.out","w",stdout);
    	int n=read();
    	int ans=S((n+2)/3+1,(n-1)/2+1);
    	int L=n-(n-1)/2+1,R=n-(n+2)/3+1;
    	if(L&1) ans-=L/2%mod,++L;
    	if(L<=R&&R%2==0) ans-=R/2%mod,--R;
    	if(L/2<=R/2) ans-=2*S(L/2,R/2)%mod;
    	cout<<(ans%mod+mod)%mod<<endl;
    	return 0;
    }
    
    

    牛奶题

    将所有区间中的元素扔到 \(\rm Trie\) 树上做 \(\rm DP\),实现的时候写的是记忆化搜索,那么遍历到的状态必然有用

    \(f_x\) 表示 \(x\) 子树中选 \(3\) 个合法的点的方案数。转移分成三个点在两个子树中的分布以及 \(K\) 的二进制表示在这位下的 \(0/1\) 来递归。三个在相同子树且 \(K\) 当前位是 \(1\) 的情况可以使用 \(\binom{siz}3\) 来快速计算。

    此时需要另设 \(g_{x,y}\) 表示两个点在 \(x\) 子树中,一个点在 \(y\) 子树中的选择方案数来满足计算 两左一右/两右一左 分布方案的需求。这部分根据点分布的位置继续讨论,其中同子树的两个点一左一右的情况仍然需要特别关照

    \(y\) 子树里面的点选到左子树时 \(x\) 中右子树的点和其形成的限制严格一些,那么可以设 \(h_{x,y}\) 表示在 \(x,y\) 子树中各选一个点的方案数,在附上对应的系数 \(siz_{ls/rs}\) 即可

    \(h\) 的转移和也是对位置讨论,这次全是平凡 case 了。

    Code Display
    const int N=1e6+10;
    int n,K,siz[N],dep[N],ls[N],rs[N],tot;
    unordered_map<int,int> dp2[N],dp3[N],dp1;
    inline int C2(int x){return x*(x-1)/2%mod;}
    inline int C3(int x){return x*(x-1)%mod*(x-2)%mod*inv6%mod;}
    inline void ins(int &p,int d,int l,int r,int st,int ed){
    	if(st<=l&&r<=ed) return p=d+1,void();
    	if(!p) dep[p=++tot]=d;
    	int mid=(l+r)>>1;
    	if(st<=mid) ins(ls[p],d-1,l,mid,st,ed);
    	if(ed>mid) ins(rs[p],d-1,mid+1,r,st,ed);
    	siz[p]=siz[ls[p]]+siz[rs[p]];
    	return ;
    }
    inline int dfs3(int x,int y){
    	if(dp3[x].count(y)) return dp3[x][y];
    	if(!x||!y) return 0;
    	if(x==1) return 1;
    	int res=0;
    	if(K>>(dep[x]-1)&1){
    		res+=dfs3(ls[x],rs[y]);
    		res+=dfs3(rs[x],ls[y]);
    		res+=siz[ls[x]]*siz[ls[y]]+siz[rs[x]]*siz[rs[y]];
    	}else{
    		res+=dfs3(ls[x],ls[y]);
    		res+=dfs3(rs[x],rs[y]);
    	}
    	return dp3[x][y]=res%mod;
    }
    inline int dfs2(int x,int y){
    	if(dp2[x].count(y)) return dp2[x][y];
    	if(x<=1||!y) return 0;
    	int res=0;
    	if(K>>(dep[x]-1)&1){
    		res+=C2(siz[ls[x]])*siz[ls[y]]+C2(siz[rs[x]])*siz[rs[y]];
    		res+=dfs2(ls[x],rs[y])+dfs2(rs[x],ls[y]);
    		res+=siz[ls[x]]*dfs3(rs[x],ls[y]);
    		res+=siz[rs[x]]*dfs3(ls[x],rs[y]);
    	}else{
    		res=dfs2(ls[x],ls[y])+dfs2(rs[x],rs[y]);
    	}
    	return dp2[x][y]=res%mod;
    }
    inline int dfs1(int x){
    	if(dp1.count(x)) return dp1[x];
    	if(x<=1) return 0;
    	int res=0;
    	if(K>>(dep[x]-1)&1){
    		res=C3(siz[ls[x]])+C3(siz[rs[x]]);
    		res+=dfs2(ls[x],rs[x]);
    		res+=dfs2(rs[x],ls[x]);
    	}else{
    		res=dfs1(ls[x])+dfs1(rs[x]);
    	}
    	return dp1[x]=res%mod;
    }
    signed main(){
    	freopen("milk.in","r",stdin);
    	freopen("milk.out","w",stdout);
    	n=read(); K=read();
    	siz[1]=1;
    	for(int i=2;i<=31;++i){
    		siz[i]=siz[i-1]*2;
    		ls[i]=rs[i]=dep[i]=i-1;
    	}
    	tot=31;
    	int rt=0;
    	while(n--){
    		int l=read(),r=read();
    		ins(rt,30,0,(1<<30)-1,l,r);
    	}
    	print(dfs1(rt));
    	return 0;
    }
    
    

    周欣题

    先求出来每次操作被 pop 光的时间,剩下可以差分处理

    将序列分块,求每个操作在其覆盖的整块以及至多两个散块的被弹出时间的最大值。为了将空间复杂度降至 \(\Theta(n)\) 那么将操作离线,对每个块处理和其相关的操作

    将 整块 散块 分别处理。

    注意到较靠后的修改操作不会比靠前的操作早删空,所以可以在时间轴上双指针。

    对于整块操作而言,维护 “至多再加入多少个元素就会被删空” 的数值 \(\rm Mx\),初始化 \(\max\{a_i\}\),为处理整体操作需要维护一个 \(tag\) ,每次整体操作将标记加一。对于不完整覆盖一个块的操作,将 \(tag\) 下方后重新计算 \(\rm Mx\) 即可。这样的操作不超过 \(2m\) 个,这部分暴力复杂度是 \(\Theta(m\sqrt n)\)

    对于不完整覆盖的操作的答案计算,做双指针的变成了每个位置。此时不能扫描完整时间轴,只遍历那些散块操作。对于整块覆盖操作影响的处理可以在时间轴上做一个前缀和,同时被删掉的位置不一定是散块操作,也可能是整块操作。

    总复杂度 \(\Theta((n+m)\sqrt n)\)

    Code Display
    const int N=2e5+10;
    int n,m,lim[N],ql[N],qr[N],qx[N],f[N],ans[N];
    vector<pair<int,int> > vec[N];
    int siz[N],cov[N],sum[N],id[N];
    inline bool in(int id,int x){return ql[id]<=x&&x<=qr[id];}
    inline bool countain(int id,int L,int R){return ql[id]<=L&&R<=qr[id];}
    int main(){
    	freopen("zx.in","r",stdin);
    	freopen("zx.out","w",stdout);
    	n=read(); m=read();
    	for(int i=1;i<=n;++i) lim[i]=read();
    	for(int i=1;i<=m;++i) ql[i]=read(),qr[i]=read(),qx[i]=read();
    	int block=sqrt(n);
    	for(int L=1,R;L<=n;L=R+1){
    		R=min(n,L+block-1);
    		int icnt=0,ccnt=0;
    		int indl=1,indr=0;
    		int Mx=0,tag=0;
    		for(int i=L;i<=R;++i) ckmax(Mx,siz[i]=lim[i]);
    		while(indl<=m&&indr<=m){
    			while(indr<m&&Mx-tag>=0){
    				++indr;
    				sum[indr]=sum[indr-1];
    				if(countain(indr,L,R)){
    					tag++;
    					cov[++ccnt]=indr;
    					sum[indr]++;
    					continue;
    				}
    				if(ql[indr]>R||qr[indr]<L) continue;
    				Mx=-2000000;
    				id[++icnt]=indr;
    				for(int i=L;i<=R;++i){
    					siz[i]-=tag;
    					if(in(indr,i)) siz[i]--;
    					ckmax(Mx,siz[i]);
    				}
    				tag=0;
    			}
    			if(countain(indl,L,R)){
    				if(Mx-tag<0) ckmax(f[indl],indr);
    				else f[indl]=m+1;
    			}
    			if(!(ql[indl]>R||qr[indl]<L)){
    				if(ql[indl]<=L&&R<=qr[indl]){
    					--tag;
    				}else{
    					Mx=-2000000;
    					for(int i=L;i<=R;++i){
    						siz[i]-=tag;
    						if(in(indl,i)) ++siz[i];
    						ckmax(Mx,siz[i]);
    					}
    					tag=0;	
    				}
    			}
    			++indl;
    		}
    		sum[m+1]=sum[m];
    		cov[++ccnt]=m+1;
    		id[++icnt]=m+1;
    		for(int i=L;i<=R;++i){
    			int indl=1,indr=0;
    			int cur=lim[i];
    			while(indl<=icnt&&indr<=icnt){
    				while(indr<icnt&&cur-(sum[id[indr]]-sum[id[indl]])>=0){
    					++indr;
    					if(in(id[indr],i)) --cur;
    				}
    				if(in(id[indl],i)){
    					if(cur-(sum[id[indr]]-sum[id[indl]])>=0){
    						f[id[indl]]=m+1;
    					}else{
    						if(in(id[indr],i)&&cur-(sum[id[indr]]-sum[id[indl]])==-1){
    							ckmax(f[id[indl]],id[indr]);
    						}else{
    							int delt=in(id[indr],i);
    							int pos=sum[id[indl]]+cur+1+delt;
    							if(pos<=ccnt) ckmax(f[id[indl]],cov[pos]);
    							else f[id[indl]]=m+1;
    						}
    					}
    				}
    				if(in(id[indl],i)) ++cur;
    				++indl;
    			}
    		}
    	}
    	for(int i=1;i<=m;++i) vec[qx[i]].emplace_back(i,f[i]);
    	for(int i=1;i<=2e5;++i){
    		sort(vec[i].begin(),vec[i].end());
    		int indic=0;
    		for(auto t:vec[i]){
    			if(indic>=t.sec) continue;
    			ans[max(indic,t.fir)]++;
    			ans[indic=t.sec]--;
    		}
    	}
    	for(int i=1;i<=m;++i) ans[i]+=ans[i-1];
    	for(int i=1;i<=m;++i) print(ans[i]);
    	return 0;
    }
    
    

  • 相关阅读:
    使用代理加快SDK Manager的下载速度
    ADT-Bundle运行的错误的排错
    转:Android开发之JNI入门-NDK从入门到精通
    Android NDK的总总误解
    mysql 数据库 一些常用语句 查内存 索引内存
    递归方法 练习编写
    ES 搜索概述
    PHP 数字类型 加 减 乘 除运算 bc函数
    php 控制反转 和 依赖注入
    Thinkphp 3 和 Thinkphp5 区别
  • 原文地址:https://www.cnblogs.com/yspm/p/16467816.html
Copyright © 2020-2023  润新知