AtCoder Grand Contest 012 A,B,(C),D题解

89 篇文章 1 订阅

AtCoder Grand Contest 012 A,B,©,D题解

A

贪心,每次删除最大的一个和最小的一个。然后答案加上最大的,删除最大的。执行 N N N次。

时间复杂度 O ( N ∗ log ⁡ 2 ( n ) ) O(N*\log_2(n)) O(Nlog2(n))

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define R(a) cin>>a
#define R2(a,b) cin>>a>>b
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int main(){
	fastio;
	int n;
	deque<int> dq;
	R(n);n*=3;
	vector<int> v;
	rb(i,1,n) {
		int ai;
		R(ai);
		v.PB(ai);
	}
	sort(ALL(v));
	reverse(ALL(v));
	rb(i,1,n)
		dq.PB(v[i-1]);
	LL rest=0;
	rb(i,1,n/3){
		dq.pop_front();
		rest+=dq.front();
		dq.pop_front();
		dq.pop_back();
	}
	cout<<rest<<endl;
	return 0;
}
/** 程序框架:
  *
  *
  *
  *
  **/

B

从后往前处理,问题变成:

每次将 v i v_i vi周围距离在 d i d_i di以内的无色的点刷成 c i c_i ci

然后可以记录 f i , j f_{i,j} fi,j表示第 i i i个点向外扩展 j j j轮,最先刷到的颜色。

然后类似最短路转移即可。

时间复杂度 O ( n ∗ max ⁡ ( d i ) ) O(n*\max(d_i)) O(nmax(di))

C

Under construction

D

我们可以发现如果 i i i可以到 j j j, j j j可以到 k k k,则 i i i可以到 k k k

  • 如果是同色,显然具有传递关系。

  • 如果不是同色,也具有传递关系

很明显,我们需要把可以到达的两两连边。答案和每一个并查集里的颜色种类和数量有关。

我们先将同色的连边,很明显,如果我们将 w i w_i wi递增排序,联通块一定是前面一段前缀,然后后面每个单独成块。

这个连边的时间复杂度为 O ( n ∗ log ⁡ 2 ( n ) ) O(n*\log_2(n)) O(nlog2(n)),( l o g log log的部分来自“启发式合并”用来维护dsu内的颜色)

但是不同颜色连边,如果暴力的化,就可能退化成 O ( n 2 ) O(n^2) O(n2)的了。

那怎么办呢?

其实我们只需要将每一个块连到 min ⁡ ( w i ) \min(w_i) min(wi)最小的异色块就行了(如果可以的化)。

这是为什么呢?

  1. 如果当前块不可以和 min ⁡ ( w i ) \min(w_i) min(wi)最小的异色块连,那么显然当前块不可能连到别的异色块。
  2. 如果可以,那么别的可以的要不也连到 min ⁡ ( w i ) \min(w_i) min(wi)最小的异色块,要不连到当前块

所以每一个块只需要连向最多一个异色块,这个用heap维护就好了。

时间复杂度 O ( n ∗ log ⁡ 2 ( n ) ) O(n*\log_2(n)) O(nlog2(n))

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define R(a) cin>>a
#define R2(a,b) cin>>a>>b
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MOD=1e9+7;
LL fact[200000+20],rfact[200000+20];
LL quick(LL A,LL B){
	if(B==0) return 1;
	LL  tmp=quick(A,B>>1);
	tmp*=tmp;
	tmp%=MOD;
	if(B&1)
		tmp*=A,tmp%=MOD;
 	return tmp;
}
LL c(int A,int B){
	return fact[A]*rfact[B]%MOD*rfact[A-B]%MOD;
}
vector<int> have[200000+20];
int fa[200000+20];
int root(int u){
	return fa[u]=(fa[u]==u? u:root(fa[u]));
}
void merge(int u,int v){
	if(root(u)!=root(v)){
		u=root(u);
		v=root(v);
		if(have[u].size()>have[v].size()){
			fa[v]=u;
			for(auto it:have[v])
				have[u].PB(it);
			have[v].clear();
		}
		else{
			fa[u]=v;
			for(auto it:have[u])
				have[v].PB(it);
			have[u].clear();
		}
	}
}
vector<int> col[200000+20];
int w[200000+20];
bool cmp(int A,int B){
	return w[A]<w[B];
}
vector<int> dsu[200000+20];
int main(){
	fastio;
	fact[0]=1ll;
	int n;
	int x,y;
	R(n);
	cin>>x>>y;
	rb(i,1,200000)
		fact[i]=fact[i-1]*i%MOD;
	rfact[200000]=quick(fact[200000],MOD-2);
	rl(i,200000-1,1)
		rfact[i]=rfact[i+1]*(i+1)%MOD;
	rfact[0]=1;
	rb(i,1,n){
		int c;
		R2(c,w[i]);
		col[c].PB(i);
		have[i].PB(c);
		fa[i]=i;
	}
	rb(i,1,n) sort(ALL(col[i]),cmp);
	priority_queue<mp,vector<mp>,greater<mp > > heap;
	rb(i,1,n){
		for(auto it:col[i]){
			if(w[it]+w[col[i][0]]<=x){
					merge(it,col[i][0]);
			}
		}
	}//连同色边 
	rb(i,1,n)
		if(root(i)==i){
			dsu[have[i][0]].PB(i);
			heap.push(II(w[col[have[i][0]][0]],have[i][0]));
		}
	rb(i,1,n){
		vector<int> ban;
		while(!heap.empty()&&heap.top().SEC==i)
			ban.PB(heap.top().FIR),heap.pop();
		if(!heap.empty())
		for(auto it:dsu[i]){
			if(w[it]+heap.top().FIR<=y){
				merge(it,col[heap.top().SEC][0]);
			}
		}
		for(auto it:ban)
			heap.push(II(it,i));
	}
	LL rest=1ll;
	rb(i,1,n)
	if(root(i)==i){
		sort(ALL(have[i]));
		int sum=0,sum_=0,las=-1;
		for(auto it:have[i]){
			if(las!=it){
				rest=rest*c(sum,sum_)%MOD;
				sum_=0;
				las=it;
			}
			sum_++;
			sum++;
		}
		rest=rest*c(sum,sum_)%MOD;
	}
	cout<<rest<<endl;
	return 0;
}
/** 程序框架:
  * DSU : 连边 
  * 1.将同色先连边 
  * 2.将异色连边
  *
  **/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值