Codeforces Round #550 (Div. 3) 题解

153 阅读4分钟

比赛链接

A

思路

记录每个字母的出现次数,然后扫一遍字母表判断即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
ll n;
ll t[40];
string s;
void print()
{
	rep(i,1,26)
		cout<<t[i]<<" ";
	cout<<endl;
}
int main()
{
	In(1,&n);
	while(n--)
	{
		cin>>s;
		memset(t,0,sizeof(t));
		ll len=(ll)s.size();
		s=' '+s;
		rep(i,1,len)
		{
			t[s[i]-'a'+1]++;
		}
		ll flag=0,is=0,cnt=0;
		rep(i,1,26)
		{
			if(t[i]>1)
			{
				flag=1;
				break;
			}
			if(t[i])
			{
				is=1;
				++cnt;
				continue;
			}
			if(is && !t[i])
				break;
		}
		if(cnt!=len || flag)
			puts("No");
		else
			puts("Yes");
	}
}

B

思路

把原数组的元素根据奇偶性分成两组,如果奇数和偶数的个数(分别记为cnta,cntbcnta,cntb)相差小于22,就可以全部删完,答案为00,否则就从较多的一组中取cntacntb1|cnta-cntb|-1个数字作为答案。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E3+10;
ll n,ans,cnta,cntb;
ll a[N],b[N];
int main()
{
	In(1,&n);
	rep(i,1,n)
	{
		ll tmp;
		In(1,&tmp);
		if(tmp%2)
			a[++cnta]=tmp;
		else
			b[++cntb]=tmp;
	}
	sort(a+1,a+cnta+1);
	sort(b+1,b+cntb+1);
	if(cnta>cntb)
	{
		ll cnt=cnta-cntb-1;
		rep(i,1,cnt)
			ans+=a[i];
	}
	else
	{
		ll cnt=cntb-cnta-1;
		rep(i,1,cnt)
			ans+=b[i];
	}
	cout<<ans<<endl;
}

C

思路

因为可以随便取来构造单调上升序列和单调下降序列,所以先从小到大排序,扫一遍数组,判断可以a[i]a[i]加到那个序列中即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n,cnta,cntb;
ll a[N],x[N],y[N];
int main()
{
	In(1,&n);
	rep(i,1,n)
		In(1,&a[i]);
	sort(a+1,a+n+1);
	x[0]=y[0]=LLm;
	rep(i,1,n)
	{
		if(x[cnta]!=a[i])
			x[++cnta]=a[i];
		else if(y[cntb]!=a[i])
			y[++cntb]=a[i];
		else
		{
			cout<<"NO"<<endl;
			return 0;
		}
	}
	sort(y+1,y+cntb+1,greater<ll>());
	puts("YES");
	Out(1,cnta);
	rep(i,1,cnta)
		Out_(1,x[i]);
	cout<<endl;
	Out(1,cntb);
	rep(i,1,cntb)
		Out_(1,y[i]);
}

D

思路

最终得到的相等元素必定是原数组中出现过的,也就是说原先出现过的这些元素都不变,其他元素各自进行11次操作。所以最优解必然是找出原数组中出现过最多的元素(记为numnum),记出现次数为maximaxi,则总的操作次数为nmaxin-maxi。然后从每个numnum开始向前扩散,最后一个numnum还要向后扩散。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n,num,maxi=LLm;
ll a[N],vis[N];
int main()
{
	In(1,&n);
	rep(i,1,n)
	{
		In(1,&a[i]);
		++vis[a[i]];
		if(vis[a[i]]>maxi)
		{
			maxi=vis[a[i]];
			num=a[i];
		}
	}
	Out(1,n-vis[num]);
	rep(i,1,n)
	{
		if(a[i]==num)
		{
			for(int j=i-1;j>=1 && a[j]!=num;--j)
			{
				if(a[j]<num)
					printf("1 %d %d",j,j+1);
				else
					printf("2 %d %d",j,j+1);
				puts("");
			}
		}
	}
	for(int i=n;i>=1;--i)
	{
		if(a[i]==num)
		{
			rep(j,i+1,n)
			{
				if(a[j]<num)
					printf("1 %d %d",j,j-1);
				else
					printf("2 %d %d",j,j-1);
				puts("");
			}
			break;
		}
	}
}

E

思路

实际上就是2626进制的加法和除法,模拟高精度即可。十进制是遇1010进位,2626进制就是遇2626进位,因此aza\rightarrow z分别对应0250\rightarrow 25

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n,add,mul;
ll x[N],y[N];
string a,b;
void print()
{
	rep(i,1,n)
		cout<<(char)(x[i]+'a');
	puts("");
}
int main()
{
	In(1,&n);
	cin>>a>>b;
	rep(i,0,n-1)
	{
		x[i+1]=a[i]-'a';
		y[i+1]=b[i]-'a';
	}
	for(int i=n;i>=1;--i)
	{
		x[i]+=y[i]+add;
		add=x[i]>25?1:0;
		if(i!=1)
			x[i]%=26;
	}
	rep(i,1,n)
	{
		y[i]=(x[i]+mul)>>1;
		mul=x[i]%2?26:0;
	}
	rep(i,1,n)
		cout<<(char)('a'+y[i]);
}

F

思路

不能有长度超过22的路,也就是说所有的点要么只有入度,要么只有出度。据此把所有的点分为两类,两个同类的点不可以连在一起,本题就转化为图上的染色问题,随便选个点bfsbfs即可。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n,m,tot;
ll head[N],cl[N];
queue<ll> q;
char s[N];
struct Edge{
	ll nxt,to;
}e[2*N];
struct edge{
	ll frm,to;
}ed[2*N];
inline void add_edge(ll u,ll v,int flag)
{
	e[++tot].nxt=head[u];
	e[tot].to=v;
	head[u]=tot;
	if(flag)
		add_edge(v,u,0);
}
void print()
{
	rep(i,1,n)
		Out_(1,cl[i]);
}
int main()
{
	cin>>n>>m;
	rep(i,0,m)
		s[i]='0';
	rep(i,1,m)
	{
		ll u,v;
		scanf("%lld %lld",&u,&v);
		add_edge(u,v,1);
		ed[i]=(edge){u,v};
	}
	q.push(1);
	rep(i,1,n)
		cl[i]=-1;
	cl[1]=1;
	while(q.size())
	{
		ll u=q.front();
		q.pop();
		bl(u,i)
		{
			ll v=e[i].to;
			if(cl[v]!=-1)
			{
				if(cl[v]==cl[u])
				{
					puts("NO");
					return 0;
				}
				continue;
			}
			cl[v]=cl[u]^1;
			q.push(v);
		}
	}
	rep(i,1,m)
	{
		ll frm=ed[i].frm;
		if(cl[frm])
			s[i]='1';
	}
	puts("YES");
	rep(i,1,m)
		cout<<s[i];
	puts("");
}

G

思路

本题和C题的区别就在于元素是要按顺序选的。记当前得到的单调上升序列的末尾元素为maximaxi,单调下降序列的末尾元素为minimini,对原数组中的元素aia_i分类讨论:

  • ai<=maxi & ai>=minia_i<=maxi\ \&\ a_i>=mini,无解。
  • ai>maxi & ai>=minia_i>maxi\ \&\ a_i>=mini,那么aia_i只能加入单调上升序列。
  • ai<mini & ai<=maxia_i<mini\ \&\ a_i<=maxi,那么aia_i只能加入单调下降序列。
  • ai>maxi & ai<minia_i>maxi\ \&\ a_i<mini,那就要看ai+1a_{i+1}aia_i的大小关系。若ai<ai+1a_i<a_{i+1},那么将aia_i加入单调上升序列显然是更优的,因为这样就可以保证单调上升序列的末尾元素尽可能小,单调下降序列的末尾元素尽可能大。否则就把aia_i加入单调下降序列。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int (i)=(st);(i)<=(ed);++(i))
#define bl(u,i) for(int (i)=head[(u)];(i);(i)=e[(i)].nxt)
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef long long ll;
typedef double db;
using namespace std;
inline void In(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		scanf("%lld",va_arg(lis,ll*));
}
inline void Out(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld\n",va_arg(lis,ll));
}
inline void Out_(ll _,...)
{
	va_list lis;
	va_start(lis,_);
	while(_--)
		printf("%lld ",va_arg(lis,ll));
}
const int N=2E5+10;
ll n;
ll a[N],ans[N];
int main()
{
	In(1,&n);
	rep(i,1,n)
		In(1,&a[i]);
	ll maxi=LLm,mini=LLM;
	rep(i,1,n)
	{
		if(a[i]<=maxi && a[i]>=mini)
		{
			puts("NO");
			return 0;
		}
		if(a[i]>maxi && a[i]>=mini)
			maxi=a[i];
		else if(a[i]<mini && a[i]<=maxi)
		{
			mini=a[i];
			ans[i]=1;
		}
		else if(a[i]>maxi && a[i]<mini)
		{
			if(a[i+1]>a[i])
				maxi=a[i];
			else
			{
				mini=a[i];
				ans[i]=1;
			}
		}
	}
	puts("YES");
	rep(i,1,n)
		Out_(1,ans[i]);
}