AtCoder Grand Contest 012 A,B,©,D题解
A
贪心,每次删除最大的一个和最小的一个。然后答案加上最大的,删除最大的。执行 N N N次。
时间复杂度 O ( N ∗ log 2 ( n ) ) O(N*\log_2(n)) O(N∗log2(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(n∗max(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(n∗log2(n)),( l o g log log的部分来自“启发式合并”用来维护dsu内的颜色)
但是不同颜色连边,如果暴力的化,就可能退化成 O ( n 2 ) O(n^2) O(n2)的了。
那怎么办呢?
其实我们只需要将每一个块连到 min ( w i ) \min(w_i) min(wi)最小的异色块就行了(如果可以的化)。
这是为什么呢?
- 如果当前块不可以和 min ( w i ) \min(w_i) min(wi)最小的异色块连,那么显然当前块不可能连到别的异色块。
- 如果可以,那么别的可以的要不也连到 min ( w i ) \min(w_i) min(wi)最小的异色块,要不连到当前块
所以每一个块只需要连向最多一个异色块,这个用heap维护就好了。
时间复杂度 O ( n ∗ log 2 ( n ) ) O(n*\log_2(n)) O(n∗log2(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.将异色连边
*
**/