Codeforces Round #649 (Div. 2) 题解 (ABCD)

https://codeforces.ml/contest/1364

A. XXXXX

如果整个数列的和不被x整除,那正好,直接输出n

如果整个数列的和被x整除,这意味着我们需要不断去掉第一个元素直到不被x整除,或者不断去掉最后一个。两者选取较优方案

如果这么做也无法不被x整除,那就-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;
#define int ll
int n,x,t,l,r,sum;
void solve(){
	cin>>n>>x; sum=0; l=inf,r=-inf;
	repeat(i,0,n){
		cin>>t;
		if(t%x!=0)l=min(l,i),r=max(r,i);
		sum+=t%x;
	}
	if(sum%x!=0){cout<<n<<endl; return;} //第一种情况
	if(l!=inf){cout<<max(n-l-1,r)<<endl; return;} //第二种情况
	cout<<-1<<endl; //第三种情况
}
signed main(){
	int T; cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

B. Most socially-distanced subsequence

显然只要保留所有“极值点”就行了。或者说,去掉所有满足 \(p_{i-1}<p_i<p_{i+1}\) 或者 \(p_{i-1}>p_i>p_{i+1}\)\(p_i\)

  • 这是因为如果 \(a\le b\le c\) 或者 \(a\ge b\ge c\),那么有 \(|a-b|+|b-c|=|a-c|\)。反过来也成立
#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;
#define int ll
int n,a[N],ans;
void solve(){
	cin>>n; ans=n;
	repeat(i,0,n)cin>>a[i];
	repeat(i,1,n-1)
	if((a[i-1]-a[i])*(a[i]-a[i+1])>0)
		ans--;
	cout<<ans<<endl;
	cout<<a[0]<<' ';
	repeat(i,1,n-1)
	if((a[i-1]-a[i])*(a[i]-a[i+1])<=0)
		cout<<a[i]<<' ';
	cout<<a[n-1]<<endl;
}
signed main(){
	int T; cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

C. Ehab and Prefix MEXs

每个 \(a_i\) 要求集合 \(\{b_1,b_2,...,b_i\}\) 包含 \([0,a_i-1]\) 但不能包含 \(a_i\)

我们发现如果 \(i>a_i\) ,那么很多 \(b_j\)\(j\le i\))暂时还不会用到(不能确定它的值),这时候可以考虑把这些还没赋值的 \(b_j\) 的位置保存起来,需要的时候再用

#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;
#define int ll
int n,a[N],ans[N];
vector<int> rec; //保存bj的位置
signed main(){
	cin>>n;
	repeat(i,0,n)cin>>a[i];
	int low=0;
	repeat(i,0,n){
		rec.push_back(i);
		repeat(j,low,a[i]){
			if(rec.empty())cout<<-1<<endl,exit(0);
			ans[rec.back()]=j,rec.pop_back();
		}
		low=a[i];
	}
	while(!rec.empty())ans[rec.back()]=1e6,rec.pop_back();
	repeat(i,0,n)cout<<ans[i]<<' ';
	return 0;
}

D. Ehab's Last Corollary

类似的一题:https://codeforces.ml/contest/1325/problem/F

这F题代码可以直接切D题。当然这F题太高级,不适合我这种div5选手,而且D题的条件宽了很多,练一下手还是挺不错的

这题非常繁琐(但不难),分成三个部分

  1. 并查集判环(不必要,\(n-1\not=m\) 就能判环)
  2. bfs树找最小环
  3. 树的最大独立集

因此我写了70+行qwq

首先,子任务2是找环,那我们就找环。假设找到一个环了呢?那好像问题就结束了,因为如果环的长度不超过k那就输出环,否则输出环上不相邻的 \(\lceil\dfrac k 2\rceil\) 个点,美滋滋(然而并不,请看下一段)

  • 但是wa(test 22)了之后我发现事情好像并不这么简单。我们要找的是无弦的环,即不存在一条边连接环上不相邻两点,否则求出的独立集就不是独立集了。一种方法是,找弦然后缩环,不知道可不可行。我的方法是,以某个点S为根建立bfs树,对于横叉边AB,就可以形成S-...-A-B-...-S的环。这样,就能求出经过S的最小环。当然,而这个最小环一定无弦因为有弦就不是最小了(但是S附近是会出现重复经过点的情况,我们把它删掉即可)。解决问题

如果无环,那说明是个树了。相信读者们对树的最大独立集再熟悉不过了,略

#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;
#define int ll
vector<int> a[N];
int n,m,k;
deque<int> rec; pair<int,int> record;
int dis[N],fa[N],ans=inf;
queue<int> q;
void bfs(int s){
	fill(dis,dis+n+1,-1); dis[s]=0;
	q.push(s); fa[s]=-1;
	while(!q.empty()){
		int x=q.front(); q.pop();
		for(auto p:a[x])
		if(p!=fa[x]){
			if(dis[p]==-1){
				dis[p]=dis[x]+1;
				fa[p]=x;
				q.push(p);
			}
			else{
				if(ans>dis[x]+dis[p]+1){
					ans=dis[x]+dis[p]+1;
					record={x,p};
				}
			}
		}
	}
}
signed main(){
	cin>>n>>m>>k;
	repeat(i,0,m){
		int x,y; cin>>x>>y;
		a[x].push_back(y);
		a[y].push_back(x);
	}
	if(n-1!=m){
		bfs(1);
		{
			for(int i=record.first;i!=1;i=fa[i])rec.push_front(i);
			for(int i=record.second;i!=1;i=fa[i])rec.push_back(i);
			int t=1;
			while(rec.front()==rec.back()){
				t=rec.front();
				rec.pop_front(),rec.pop_back();
			}
			rec.push_back(t);
		} 
		if((int)rec.size()<=k){
			cout<<2<<endl;
			cout<<rec.size()<<endl;
			for(auto i:rec)cout<<i<<' ';
		}
		else{
			cout<<1<<endl;
			repeat(i,0,(k+1)/2)
				cout<<rec[i*2]<<' ';
		}
	}
	else{
		bfs(1);
		int cnt=0;
		repeat(i,1,n+1)cnt+=dis[i]%2==1;
		int co=cnt>=(k+1)/2;
		repeat(i,1,n+1)
		if(dis[i]%2==co)
			rec.push_back(i);
		cout<<1<<endl;
		repeat(i,0,(k+1)/2)
			cout<<rec[i]<<' ';
	}
	return 0;
}
posted @ 2020-06-14 01:11  axiomofchoice  阅读(120)  评论(2编辑  收藏  举报