AtCoder Grand Contest 011(AGC011) A~C题解

89 篇文章 1 订阅

AtCoder Grand Contest 011(AGC011) A~C题解

A

贪心,每一个巴士都尽可能安排在前面。

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

/*
{By GWj

*/
#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 n;
int c,k,t[100000+20];

int main(){
	fastio;
	R(n);
	R2(c,k);
	rb(i,1,n){
		R(t[i]);
	}
	sort(t+1,t+1+n);
	int l=1;
	int rest=0;
	rb(i,1,n){
		if(t[i]-t[l]>k||i-l+1>c){
			l=i;
			rest++;
		}
	}
	rest++;
	cout<<rest<<endl;
	return 0;
}

B

若所有的巴士升序排序,那么最后剩下的颜色可以是它的后缀之一。

如果检验 i i i号位置的颜色是否可以留下,我们可以从小往大合并。这样肯定是一段一段的,其中最后一段的长度就是答案。

时间复杂度 O ( n ) O(n) O(n)

/*
{By GWj

*/
#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 n;
int a[100000+20];

int main(){
	fastio;
	R(n);
	rb(i,1,n) R(a[i]);
	sort(a+1,a+1+n);
	int las=0;
	LL sum=0;
	while(1){
		int index=las+1;
		sum+=a[las+1];
		while(index!=n&&sum*2>=a[index+1]){
			index++;
			sum+=a[index];
		}
		if(index==n){
			cout<<n-las<<endl;break;
			
		}
		las=index;	
	}
	return 0;
}

C

我们可以给每一个联通块打上一个标记,我们不妨设它是这个联通快内最小的点 ( a , b ) (a,b) (a,b)

问题转换成:

如果一个点 ( a , b ) (a,b) (a,b)不能连到更小的点 ( a ′ , b ′ ) (a\prime,b\prime) (a,b)的化, a n s + + ans++ ans++

那怎么判断一个点 ( a , b ) (a,b) (a,b)是否可以连到更小的点呢?

如果 a a a可以到达的点中,最小值 < a <a <a ( a , b ) (a,b) (a,b)可以到达更小的 ( a ′ , b ′ ) (a\prime,b\prime) (a,b)其中 a > a ′ a>a\prime a>a

如果不可以,那么如果 a = a ′ a=a\prime a=a时, ∀ b ′ ≥ b \forall b\prime\geq b bb,则 ( a , b ) (a,b) (a,b)不能到达更小的点。

假设从 a a a走奇数步可以到达 a a a,则 b b b走奇数步到达的 b ′ b\prime b中的最小值要 ≥ b \geq b b

对于偶数也一样。

每一个点经过奇数步/偶数步到达的点的最小值可以用“最短路dp算出”

然后再判断一下没有与别的连边的就行了。

时间复杂度 O ( E ∗ log ⁡ 2 ( E ) ) O(E*\log_2(E)) O(Elog2(E)),但是用 0 − 1 b f s 0-1bfs 01bfs的思想可以优化到 O ( E ) O(E) O(E)

/*
{By GWj

*/
#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 MAXN=100000+20;
int dp[MAXN][2];
vector<int> g[MAXN];
int n,m;
int save=0;
int main(){
	fastio;
	R2(n,m);
	rb(i,1,m){
		int u,v;
		R2(u,v);
		g[u].PB(v);
		g[v].PB(u);
	}
	set<pair<int,pair<int,bool> >> heap;
	memset(dp,63,sizeof(dp));
	rb(i,1,n)
		dp[i][0]=i,heap.insert(II(i,II(i,0)));
	while(!heap.empty()){
		pair<int,pair<int,bool> > now=*heap.begin();
		heap.erase(heap.begin());
		int i,j,val;
		i=now.SEC.FIR;
		j=now.SEC.SEC;
		val=now.FIR;
		if(dp[i][j]!=val) continue;
		for(auto it:g[i]){
			if(dp[it][j^1]>dp[i][j]){
				dp[it][j^1]=dp[i][j];
				heap.insert(II(val,II(it,j^1)));
			}
		}
	}
	int N=0;
	rb(i,1,n){
		N+=g[i].empty();
	}
	int save1=0,save0=0,save3=0;
	rb(i,1,n){
		if(g[i].size()){
			if(dp[i][0]==i){
				save3+=dp[i][1]>=i;
				save0++;
			}
			if(dp[i][1]>=i){
				save1++;
			}
		}
		
	}
	LL rest=1ll*N*n*2-1ll*N*N;
	rb(i,1,n){
		if(g[i].size())
		if(min(dp[i][0],dp[i][1])==i){
			if(dp[i][0]==i&&dp[i][1]==i){
				rest+=save3;
			}
			else{
				rest+=save0;
			}
		}
	}
	cout<<rest<<endl;
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值