题解-ABC218

回归了原本的 ABC 难度,可惜我很久没打没有手速被打爆了。

https://atcoder.jp/contests/abc218/tasks

A

直接模拟

#include<bits/stdc++.h>
using namespace std;
int n;
char s[10]; 
int main(){
	scanf("%d%s",&n,s+1);
	if(s[n]=='o')puts("Yes");
	else puts("No");
	return 0;
}

B

直接模拟

#include<bits/stdc++.h>
using namespace std;
int main(){
	for(int i=1;i<=26;i++){
		int x;
		scanf("%d",&x);
		printf("%c",x+'a'-1);
	}
	return 0;
}

C

考虑将第二图的第一个位置放到第一个第一个位置上,然后比较,较小的模拟

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
struct node{
	char mp[1005][1005];
}s,t,tmp;
int n;
void print(node a){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)printf("%c",a.mp[i][j]);
		puts("");
	}puts("");
}
bool check(node a,node b){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a.mp[i][j]!=b.mp[i][j]){
				return 0;
			}
		}
	}
	return 1;
}
void work(node &a,int x0,int y0){
	node b;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)b.mp[i][j]='.';
	int x=0,y=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a.mp[i][j]=='#'){
				x=i,y=j;
				break;
			}
		}
		if(x||y)break;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(a.mp[i][j]=='#'){
				b.mp[x0+i-x][y0+j-y]='#';
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			a.mp[i][j]=b.mp[i][j];
		}
	}
}
void rotate(node &a){
	node b;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			b.mp[n-j+1][i]=a.mp[i][j];	
		} 
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			a.mp[i][j]=b.mp[i][j];
		}
	}
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%s",s.mp[i]+1);
	for(int i=1;i<=n;i++)scanf("%s",t.mp[i]+1);
	int cnts=0,cntt=0;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cnts+=s.mp[i][j]=='#';
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cntt+=t.mp[i][j]=='#';
	if(cnts!=cntt){
		puts("No");
		return 0;
	}
	int x=0,y=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(s.mp[i][j]=='#'){
				x=i,y=j;
				break;
			}
		}
		if(x||y)break;
	}
	for(int T=1;T<=4;T++){
		rotate(t);
		for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)tmp.mp[i][j]=t.mp[i][j];
		work(tmp,x,y);
		if(check(s,tmp)){
			puts("Yes");
			return 0;
		}
	}
	puts("No");
	return 0;
}

D

枚举两个点作为左下角,右上角,然后用map判断即可。

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
struct node{
	int x,y;
}p[2005];
int n;
map<pair<int,int>,int>m;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y),m[mp(p[i].x,p[i].y)]++;
	int ans=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			if(p[i].x<p[j].x&&p[i].y<p[j].y){
				if(m.find(mp(p[i].x,p[j].y))!=m.end()&&m.find(mp(p[j].x,p[i].y))!=m.end()){
					ans++;
				}
			}
		}
	}
	printf("%d
",ans);
	return 0;
}

E

求出最小生成树,其中正权边不能选,取剩下所有正确边。

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
const int maxn=200005;
struct edge{
	int u,v,w;
	friend bool operator<(edge a,edge b){return a.w<b.w;}
}e[maxn];
int n,m,fa[maxn];
int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
inline void Merge(int x,int y){fa[Find(x)]=Find(y);}
ll ans;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w),ans+=e[i].w>0?e[i].w:0;
	sort(e+1,e+1+m);
	for(int i=1;i<=m;i++){
		if(Find(e[i].u)!=Find(e[i].v)){
			if(e[i].w>0)ans-=e[i].w;
			Merge(e[i].u,e[i].v);
		}
	}
	printf("%lld
",ans);
	return 0;
}

F

求出最短路径树,只有在最短路径树上的路径上的边才有可能改变最短路,去掉暴力bfs即可,复杂度 (O(nm))

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
const int maxn=405;
int n,m,g[maxn][maxn],s[maxn*maxn],t[maxn*maxn],dis[maxn],pre[maxn],d[maxn];
queue<int> q;
bool vis[maxn],mark[maxn];
int bfs(int x,int y){
	for(int i=1;i<=n;i++)vis[i]=0,dis[i]=-1;
	q.push(1);
	vis[1]=1;
	dis[1]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int v=1;v<=n;v++){
			if(u==x&&v==y)continue;
			if(g[u][v]&&!vis[v]){
				dis[v]=dis[u]+1;
				vis[v]=1;
				q.push(v);
			}
		}
	}
	return dis[n];
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d%d",s+i,t+i),g[s[i]][t[i]]=1;
	for(int i=1;i<=n;i++)vis[i]=0,d[i]=-1;
	q.push(1);
	vis[1]=1;d[1]=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int v=1;v<=n;v++){
			if(g[u][v]&&!vis[v]){
				d[v]=d[u]+1;
				pre[v]=u;
				vis[v]=1;
				q.push(v);
			}
		}
	}
	if(d[n]==-1){
		for(int i=1;i<=m;i++)puts("-1");
		return 0;
	}
	int x=n;
	while(x!=1){
		mark[x]=1;
		x=pre[x];
	}
	for(int i=1;i<=m;i++){
		if(!mark[t[i]])printf("%d
",d[n]);
		else{
			if(s[i]!=pre[t[i]])printf("%d
",d[n]);
			else{
				printf("%d
",bfs(s[i],t[i]));
			}
		}
	}
	return 0;
}

G

博弈,然后瞎转移,用数据结构维护中位数即可。

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
const int maxn=100005;
struct node{
	int val,key,son[2],sz;
}tr[maxn*40];
int tot,rt,dep[maxn];
int new_node(int v){
	tr[++tot]=node{v,rand(),0,0,1};
	return tot;
}
void pushup(int p){
	tr[p].sz=tr[tr[p].son[0]].sz+tr[tr[p].son[1]].sz+1;
}
int merge(int u,int v){
	if(!u||!v)return u|v;
	if(tr[u].key<tr[v].key){
		tr[u].son[1]=merge(tr[u].son[1],v);
		pushup(u);
		return u;
	}else{
		tr[v].son[0]=merge(u,tr[v].son[0]);
		pushup(v);
		return v;
	}
}
void split(int p,int &x,int &y,int k){
	if(!p)x=y=0;
	else{
		if(tr[p].val<=k){
			x=p;
			split(tr[p].son[1],tr[x].son[1],y,k); 
		}else{
			y=p;
			split(tr[p].son[0],x,tr[y].son[0],k);
		}
		pushup(p);
	}
}
void ins(int &p,int v){
	int x,y;
	split(p,x,y,v);
	p=merge(merge(x,new_node(v)),y);
}
void del(int &p,int v){
	int x,y,z;
	split(p,x,z,v);
	split(x,x,y,v-1);
	y=merge(tr[y].son[0],tr[y].son[1]);
	p=merge(merge(x,y),z);
}
int ath(int p,int a){
	if(tr[tr[p].son[0]].sz>=a)return ath(tr[p].son[0],a);
	else{
		a-=tr[tr[p].son[0]].sz;
		if(a==1)return tr[p].val;
		return ath(tr[p].son[1],a-1);
	}
}
int n,a[maxn],f[maxn];
vector<int> vec[maxn];
void dfs(int u,int fa){
	int cnt=0;
	ins(rt,a[u]);
	if(dep[u]&1)f[u]=0;
	else f[u]=1e9+1; 
	for(auto v:vec[u]){
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		dfs(v,u);
		if(dep[u]&1)f[u]=max(f[u],f[v]);
		else f[u]=min(f[u],f[v]);
		cnt++;
	}
	if(cnt==0){
		if(dep[u]&1)f[u]=ath(rt,(dep[u]+1)/2);
		else f[u]=(ath(rt,dep[u]/2)+ath(rt,dep[u]/2+1))/2;
		del(rt,a[u]);
		return;
	}
	del(rt,a[u]);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);
		vec[u].pb(v);vec[v].pb(u);
	}
	dep[1]=1;dfs(1,0);
	printf("%d
",f[1]);
	return 0;
}

H

显然这东西有凸性,于是 wqs 二分+普及组dp即可。

/*
  Author : Flying_Bird (ZCR)
  url : https://nmsl.com
  Time : 2021/09/01
*/
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
const ll maxn=200005;
ll n,R,a[maxn];
ll dp[maxn][2],cnt[maxn][2];
bool check(ll m){
	dp[1][1]=m;cnt[1][1]=1;
	for(ll i=2;i<=n;i++){
		if(dp[i-1][0]<dp[i-1][1]+a[i-1]){
			dp[i][0]=dp[i-1][1]+a[i-1];
			cnt[i][0]=cnt[i-1][1];
		}else{
			dp[i][0]=dp[i-1][0];
			cnt[i][0]=cnt[i-1][0];
		}
		if(dp[i-1][1]>dp[i-1][0]+a[i-1]){
			dp[i][1]=dp[i-1][1]+m;
			cnt[i][1]=cnt[i-1][1]+1;
		}else{
			dp[i][1]=dp[i-1][0]+a[i-1]+m;
			cnt[i][1]=cnt[i-1][0]+1;
		}
	}
	if(dp[n][0]>dp[n][1]){
		return cnt[n][0]>R;
	}else{
		return cnt[n][1]>R;
	}
}
int main(){
	scanf("%lld%lld",&n,&R);
	for(ll i=1;i<n;i++)scanf("%lld",a+i);
	ll l=-4e9,r=4e9,ans=-4e9;
	while(l<=r){
		ll mid=(l+r)>>1;
		check(mid);
		if(check(mid)){
			r=mid-1;
		}else{
			ans=mid;
			l=mid+1;
		}
	}
	check(ans);
	if(dp[n][0]>dp[n][1]){
		printf("%lld
",dp[n][0]-ans*R);
	}else{
		printf("%lld
",dp[n][1]-ans*R);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/zcr-blog/p/15256962.html