zoukankan      html  css  js  c++  java
  • 「雅礼集训 2017 Day1」 解题报告

    「雅礼集训 2017 Day1」市场

    挺神仙的一题。涉及区间加、区间除、区间最小值和区间和。虽然标算就是暴力,但是复杂度是有保证的。

    我们知道如果线段树上的一个结点,(max=min) 或者 (max=min+1) 并且 (d|max),是可以直接剪掉的。

    我们定义线段树上一个结点的势能为 (log(max-min)),那么我们每执行一次区间除,都会引起势能的减小。

    但是执行区间加时我们涉及 (log n) 个结点,最差情况下会将它们的势能恢复为 (log(max-min))

    所以总时间复杂度就是势能总和,不难分析为 (O(nlog d+qlog nlog d))

    类似的,我们可以分析区间开根区间加的时间复杂度,在此就不赘述了。

    (Code Below:)

    #include <cstdio>
    #include <iostream>
    #define int long long
    #define lson (rt<<1)
    #define rson (rt<<1|1)
    using namespace std;
    const int maxn=100000+10;
    const int inf=1e18;
    int n,m,a[maxn],sum[maxn<<2],Max[maxn<<2],Min[maxn<<2],add[maxn<<2];
    
    inline int read(){
    	register int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return (f==1)?x:-x;
    }
    
    inline void pushup(int rt){
    	sum[rt]=sum[lson]+sum[rson];
    	Max[rt]=max(Max[lson],Max[rson]);
    	Min[rt]=min(Min[lson],Min[rson]);
    }
    
    inline void pushtag(int rt,int C,int len){
    	sum[rt]+=C*len;
    	Max[rt]+=C;Min[rt]+=C;add[rt]+=C;
    }
    
    inline void pushdown(int rt,int len){
    	if(add[rt]){
    		pushtag(lson,add[rt],len-(len>>1));
    		pushtag(rson,add[rt],len>>1);
    		add[rt]=0;
    	}
    }
    
    void build(int l,int r,int rt){
    	if(l == r){
    		sum[rt]=Max[rt]=Min[rt]=a[l];
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,lson);
    	build(mid+1,r,rson);
    	pushup(rt);
    }
    
    void update_plu(int L,int R,int C,int l,int r,int rt){
    	if(L <= l && r <= R){
    		sum[rt]+=(r-l+1)*C;
    		Max[rt]+=C;Min[rt]+=C;add[rt]+=C;
    		return ;
    	}
    	pushdown(rt,r-l+1);
    	int mid=(l+r)>>1;
    	if(L <= mid) update_plu(L,R,C,l,mid,lson);
    	if(R > mid) update_plu(L,R,C,mid+1,r,rson);
    	pushup(rt);
    }
    
    void update_div(int L,int R,int C,int l,int r,int rt){
    	if(L <= l && r <= R){
    		int A,B;
    		if(Max[rt]<0) A=(Max[rt]-C+1)/C;
    		else A=Max[rt]/C;
    		if(Min[rt]<0) B=(Min[rt]-C+1)/C;
    		else B=Min[rt]/C;
    		if(Max[rt]-A==Min[rt]-B){
    			pushtag(rt,A-Max[rt],r-l+1);
    			return ;
    		}
    	}
    	pushdown(rt,r-l+1);
    	int mid=(l+r)>>1;
    	if(L <= mid) update_div(L,R,C,l,mid,lson);
    	if(R > mid) update_div(L,R,C,mid+1,r,rson);
    	pushup(rt);
    }
    
    int query_min(int L,int R,int l,int r,int rt){
    	if(L <= l && r <= R){
    		return Min[rt];
    	}
    	pushdown(rt,r-l+1);
    	int mid=(l+r)>>1,ans=inf;
    	if(L <= mid) ans=min(ans,query_min(L,R,l,mid,lson));
    	if(R > mid) ans=min(ans,query_min(L,R,mid+1,r,rson));
    	return ans;
    }
    
    int query_sum(int L,int R,int l,int r,int rt){
    	if(L <= l && r <= R){
    		return sum[rt];
    	}
    	pushdown(rt,r-l+1);
    	int mid=(l+r)>>1,ans=0;
    	if(L <= mid) ans+=query_sum(L,R,l,mid,lson);
    	if(R > mid) ans+=query_sum(L,R,mid+1,r,rson);
    	return ans;
    }
    
    signed main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	build(1,n,1);
    	int op,l,r,k;
    	for(int i=1;i<=m;i++){
    		op=read(),l=read(),r=read();l++;r++;
    		if(op==1) k=read(),update_plu(l,r,k,1,n,1);
    		if(op==2) k=read(),update_div(l,r,k,1,n,1);
    		if(op==3) printf("%lld
    ",query_min(l,r,1,n,1));
    		if(op==4) printf("%lld
    ",query_sum(l,r,1,n,1));
    	}
    	return 0;
    }
    

    「雅礼集训 2017 Day1」矩阵

    构造题。

    发现无解的情况就是全空的情况,特判掉即可。

    现在考虑怎么算出最少步数。

    发现只要第 (i) 行有黑色,那么第 (i) 列会在 (tot_{white}) 步变成全黑,所以我们来构造一行全黑的,然后将整个棋盘染成黑色。

    那么每行取个最小值即可,累加一下。

    (Code Below:)

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=1000+10;
    int n,m,h[maxn],l[maxn],ans,sum;
    char s[maxn][maxn];
    
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	int flag=0;
    	for(int i=1;i<=n;i++){
    		scanf("%s",s[i]+1);
    		for(int j=1;j<=n;j++)
    			if(s[i][j]=='#'){
    				flag=1;
    				h[i]++;l[j]++;
    			}
    	}
    	if(!flag){
    		printf("-1
    ");
    		return 0;
    	}
    	ans=n;
    	for(int i=1;i<=n;i++) ans=min(ans,n-h[i]+!l[i]);
    	for(int i=1;i<=n;i++) sum+=l[i]!=n;
    	printf("%d
    ",ans+sum);
    	return 0;
    }
    
  • 相关阅读:
    计算机技术与软件专业以考代评政策之我见
    关于设立运营部门的我的几点建议
    自助式微软BI工具PowerPivot简介!
    写在两年前的公司新版CRM系统需求探讨
    实时音视频开发之开源项目
    vue3.0 使用vue脚手架生成vue项目 运行mapbox 3D地图例子
    Vue开发工具Visual Studio Code 配置插件
    sip协议开源实现
    redis操作
    SIP协议 Java开源jar
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10193771.html
Copyright © 2011-2022 走看看