zoukankan      html  css  js  c++  java
  • Codeforces Round #665 (Div. 2) 题解 (CDEF)

    C. Mere Array

    大意:给定一个序列,你可以交换两个数,要求这两个数的gcd等于整个序列的最小值。问是否可以让序列单调不下降

    显然,想要交换两个数a,b,我们可以让a与最小元素交换,再让b与最小元素交换,再让a与最小元素交换。因此,一个数能否自由移动,就看它与最小元素的gcd是否等于最小元素。我们把可以自由移动的数排个序就好了

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
    const ll mod=(1?1000000007:998244353);
    #define int ll
    int a[N],b[N];
    void Solve(){
    	int n=read(),f=1;
    	repeat(i,0,n)
    		a[i]=b[i]=read();
    	int m=*min_element(a,a+n);
    	sort(b,b+n);
    	repeat(i,0,n)
    	if(b[i]!=a[i] && __gcd(a[i],m)!=m)
    		f=false;
    	cout<<(f?"YES":"NO")<<endl;
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    D. Maximum Distributed Tree

    大意:给边赋值,使得所有不同的路径的边权之和之和最大。还要求边权之积等于k且边权里的1的数量最小

    首先,如果边权数不足n-1,那就补1;如果边权数超过n-1,那就把最大的(边权数-n+2)个数删除,补上被删除的数乘积。这样边权数就是n-1了

    一条边的贡献为边权乘以(整个树被这条边分割成的两个子树大小的乘积)。我们先算出所有边权、统计次数,放到两个数组里,对这两个数组分别排个序,依次匹配(排序不等式)

    注意排序前不要取模!

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
    const ll mod=(1?1000000007:998244353);
    #define int ll
    vector<int> a[N],w,v;
    int sz[N],n;
    void dfs(int x,int fa=-1){
    	sz[x]=1;
    	for(auto p:a[x])if(p!=fa){
    		dfs(p,x);
    		v<<(sz[p]*(n-sz[p])); //"<<" means push_back
    		sz[x]+=sz[p];
    	}
    }
    void Solve(){
    	n=read();
    	repeat(i,1,n+1)a[i].clear(); w.clear(); v.clear();
    	repeat(i,0,n-1){
    		int x=read(),y=read();
    		a[x]<<y; a[y]<<x; //"<<" means push_back
    	}
    	int m=read();
    	repeat(i,0,m)w<<read(); //"<<" means push_back
    	repeat(i,m,n-1)w<<1ll; //"<<" means push_back
    	dfs(1);
    	ll ans=0;
    	sort(w.begin(),w.end());
    	while((int)w.size()>n-1){
    		int a=w.back(); w.pop_back();
    		int b=w.back(); w.pop_back();
    		w<<(a*b%mod); //"<<" means push_back
    	}
    	sort(v.begin(),v.end());
    	repeat(i,0,n-1)ans+=v[i]%mod*w[i]%mod;
    	ans%=mod;
    	cout<<ans<<endl;
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    E. Divide Square

    大意:边长为1000000的矩形内有一些竖线或横线,所有线都会碰到矩形边界。问这些线把矩形分成几部分

    找了一下规律,发现答案为1+交点数+一下就可以把大矩形分成两块的线段数。主要难点是统计交点数

    根据扫描线的操作,我们让一条水平的扫描线从下往上扫过整个大矩形。如果扫描线碰到竖线的下端点,我们让这个线段树的(竖线的横坐标)这个位置加1,碰到上端点,那就这个位置减1。如果扫描线碰到横线,那就统计线段树里的区间和

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=200010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
    const ll mod=(1?1000000007:998244353);
    #define int ll
    struct LR{
    	int y,l,r;
    }a[N];
    struct event{
    	int x,y,d;
    };
    struct seg{
    	#define U(a,b) (a+b)
    	ll a0=0;
    	int n; ll a[1024*1024*2];
    	void init(int inn){
    		for(n=1;n<inn;n<<=1);
    		repeat(i,0,n)a[n+i]=0;
    		repeat_back(i,1,n)up(i);
    	}
    	void up(int x){
    		a[x]=U(a[x<<1],a[(x<<1)^1]);
    	}
    	void update(int x,ll k){
    		a[x+=n]+=k;
    		while(x>>=1)up(x);
    	}
    	ll query(int l,int r){
    		ll ans=a0;
    		for(l+=n-1,r+=n+1;l^r^1;l>>=1,r>>=1){
    			if(~l & 1)ans=U(ans,a[l^1]);
    			if(r & 1)ans=U(ans,a[r^1]);
    		}
    		return ans;
    	}
    }tr;
    vector<event> e;
    void Solve(){
    	int n=read(),m=read(); tr.init(1000010);
    	ll ans=1;
    	repeat(i,0,n){
    		a[i].y=read();
    		a[i].l=read();
    		a[i].r=read();
    	}
    	sort(a,a+n,[](LR a,LR b){return a.y<b.y;});
    	repeat(i,0,m){
    		int x=read(),u=read(),d=read();
    		int t=(u==0)+(d==1000000);
    		e<<(event){x,u,1}; //"<<" means push_back
    		e<<(event){x,d+1,-1}; //"<<" means push_back
    		ans+=(t==2);
    	}
    	sort(e.begin(),e.end(),[](event a,event b){return a.y>b.y;});
    	repeat(i,0,n){
    		int t=(a[i].l==0)+(a[i].r==1000000);
    		while(!e.empty() && e.back().y<=a[i].y){
    			tr.update(e.back().x,e.back().d);
    			e.pop_back();
    		}
    		ans+=tr.query(a[i].l,a[i].r);
    		ans+=(t==2);
    	}
    	cout<<ans<<endl;
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; //T=read();
    	while(T--)Solve();
    	return 0;
    }
    

    F. Reverse and Swap

    大意:维护一个数据结构,可以实现单点修改、区间求和、翻转、交换(具体看原题)

    因为翻转、交换操作满足交换率和结合律,因此这题就是一个魔改线段树。对于翻转操作来说,相当于在某一层的所有节点,交换左右儿子,然后懒标记下放,让儿子们也交换一下左右儿子。对于交换操作来说,相当于交换某一层的所有节点的左右儿子,不用下放懒标记。但是某一层的节点数是O(n)显然不行。因此对于这两种操作,需要一个特殊的懒标记,表示这个节点往下走多少层后,需要执行翻转/交换操作

    什么,你说你的线段树不能交换左右儿子?那就换成可持久化动态树套仙人掌吧

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
    const int N=1000010; typedef long long ll; const int inf=~0u>>2; const ll INF=~0ull>>2; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;} typedef double lf; const lf pi=acos(-1.0); lf readf(){lf x; if(scanf("%lf",&x)==-1)exit(0); return x;} typedef pair<ll,ll> pii; template<typename T> void operator<<(vector<T> &a,T b){a.push_back(b);}
    #define int ll
    int in[N];
    struct seg{
    	#define U(x,y) (x+y)
    	#define a0 0
    	void toz(ll x1,ll x2){
    		z1^=x1,z2^=x2;
    	}
    	ll a,z1,z2; seg *lc,*rc;
    	void init(int,int);
    	void up(){a=U(lc->a,rc->a);}
    	void down(int l,int r){
    		if(z1&1)swap(lc,rc),z1^=3;
    		if(z2&1)swap(lc,rc);
    		if(l<r){
    			lc->toz(z1>>1,z2>>1);
    			rc->toz(z1>>1,z2>>1);
    		}
    		z1=z2=0;
    	}
    	void update(int l,int r,ll k1,ll k2){
    		z1^=k1;
    		z2^=k2;
    		down(l,r);
    	}
    	void change(int l,int r,ll x,ll y){
    		if(l==x && r==x){
    			down(l,r);
    			a=y;
    			return;
    		}
    		if(x<l || x>r){down(l,r); return;}
    		int m=(l+r)/2; down(l,r);
    		lc->change(l,m,x,y);
    		rc->change(m+1,r,x,y);
    		up();
    	}
    	ll query(int l,int r,int x,int y){
    		x=max(x,l); y=min(y,r); if(x>y)return a0;
    		down(l,r);
    		if(x==l && y==r)return a;
    		int m=(l+r)/2;
    		return U(lc->query(l,m,x,y),rc->query(m+1,r,x,y));
    	}
    }tr[N*2],*pl;
    void seg::init(int l,int r){
    	if(l==r){a=in[l]; return;}
    	int m=(l+r)/2;
    	lc=++pl; lc->init(l,m);
    	rc=++pl; rc->init(m+1,r);
    	up();
    }
    void init(int l,int r){
    	pl=tr; tr->init(l,r);
    }
    void Solve(){
    	int nn=read(),q=read(); int n=1<<nn;
    	repeat(i,0,n)in[i]=read();
    	init(0,n-1);
    	while(q--){
    		int op=read();
    		if(op==1){
    			int x=read()-1,y=read();
    			tr->change(0,n-1,x,y);
    		}
    		else if(op==2){
    			int x=read(); x=nn-x;
    			tr->update(0,n-1,1<<x,0);
    		}
    		else if(op==3){
    			int x=read(); x=max(0ll,(nn-x)-1);
    			tr->update(0,n-1,0,1<<x);
    		}
    		else{
    			int x=read()-1,y=read()-1;
    			cout<<tr->query(0,n-1,x,y)<<endl;
    		}
    	}
    }
    signed main(){
    	//freopen("data.txt","r",stdin);
    	int T=1; //T=read();
    	while(T--)Solve();
    	return 0;
    }
    
  • 相关阅读:
    CSRF的防御解决过程
    Spring生态研习【三】:Spring-kafka
    Spring生态研习【二】:SpEL(Spring Expression Language)
    Spring生态研习【一】:定时任务Spring-task
    给定一个大的任务,需要在考虑性能的情况下,快速处理完,并报告结果
    给定一个大于2的偶数,将其分解为两个质数的和
    一个求解平方根的算法题
    Kafka研究【一】:bring up环境
    LB+nginx+tomcat7集群模式下的https请求重定向(redirect)后变成http的解决方案
    IDEA使用笔记(八)——自动生成 serialVersionUID 的设置
  • 原文地址:https://www.cnblogs.com/axiomofchoice/p/13544054.html
Copyright © 2011-2022 走看看