CF1032C Playing Piano 题解

题目翻译已经很简洁了,这里不再多说什么了。

观察数据范围, 1 ≤ b i ≤ 5 1 \le b_i \le 5 1bi5,说明 b i b_i bi 的取值范围很有限,不难想到递推或爆搜。

现在设 f i , j f_{i,j} fi,j 表示 b i b_i bi 是否可以取到 j j j。下面为递推方法:

  • a i < a i + 1 a_i < a_{i+1} ai<ai+1 f i , j = 1 f_{i,j} = 1 fi,j=1,则对所有 k > j k > j k>j,有 f i + 1 , k = 1 f_{i+1,k} = 1 fi+1,k=1

  • a i > a i + 1 a_i > a_{i+1} ai>ai+1 f i , j = 1 f_{i,j} = 1 fi,j=1,则对所有 k < j k < j k<j,有 f i + 1 , k = 1 f_{i+1,k} = 1 fi+1,k=1

  • a i = a i + 1 a_i = a_{i+1} ai=ai+1 f i , j = 1 f_{i,j} = 1 fi,j=1,则对所有 k ≠ j k \neq j k=j,有 f i + 1 , k = 1 f_{i+1,k} = 1 fi+1,k=1

若对于 i ∈ [ 1 , 5 ] i \in [1,5] i[1,5] ∃ f n , i = 1 \exists f_{n,i}=1 fn,i=1,则表示有答案,否则表示无答案。

对于有答案的情况,我们考虑倒序寻找答案。如果 f i , j = 1 f_{i,j} = 1 fi,j=1,则对于 k ∈ [ 1 , 5 ] k \in [1,5] k[1,5] ∃ f i − 1 , k = 1 \exists f_{i-1,k}=1 fi1,k=1。故一定能找到一组答案。

代码如下。

#include<bits/stdc++.h>
using namespace std;
#define Getchar() p1==p2 and (p2=(p1=Inf)+fread(Inf,1,1<<21,stdin),p1==p2)?EOF:*p1++
#define Putchar(c) p3==p4 and (fwrite(Ouf,1,1<<21,stdout),p3=Ouf),*p3++=c
char Inf[1<<21],Ouf[1<<21],*p1,*p2,*p3=Ouf,*p4=Ouf+(1<<21);
inline void read(int &x,char c=Getchar())
{
	bool f=c!='-';
	x=0;
	while(c<48 or c>57) c=Getchar(),f&=c!='-';
	while(c>=48 and c<=57) x=(x<<3)+(x<<1)+(c^48),c=Getchar();
	x=f?x:-x;
}
inline void write(int x)
{
	if(x<0) Putchar('-'),x=-x;
	if(x>=10) write(x/10),x%=10;
	Putchar(x^48);
}
int n,a[100010],ans[100010];
bool f[100010][6];
int main()
{
	read(n),f[1][1]=f[1][2]=f[1][3]=f[1][4]=f[1][5]=1;
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=2;i<=n;i++)
		if(a[i]>a[i-1]) for(int j=2;j<=5;j++) for(int k=1;k<j;k++) f[i][j]|=f[i-1][k];
		else if(a[i]<a[i-1]) for(int j=1;j<=4;j++) for(int k=j+1;k<=5;k++) f[i][j]|=f[i-1][k];
		else for(int j=1;j<=5;j++) for(int k=1;k<=5;k++) if(j!=k) f[i][j]|=f[i-1][k];
	if(!f[n][1] && !f[n][2] && !f[n][3] && !f[n][4] && !f[n][5])
	{
		cout<<-1;
		return 0;
	}
	for(int i=1;i<=5;i++) if(f[n][i]) ans[n]=i;
	for(int i=n-1;i;i--)
	{
		if(a[i]<a[i+1])
		{
			for(int j=1;j<ans[i+1];j++) if(f[i][j]) ans[i]=j;
		}else if(a[i]>a[i+1])
		{
			for(int j=ans[i+1]+1;j<=5;j++) if(f[i][j]) ans[i]=j;
		}else
		{
			for(int j=1;j<=5;j++) if(f[i][j] && j!=ans[i+1]) ans[i]=j;
		}
	}
	for(int i=1;i<=n;i++) write(ans[i]),Putchar(' ');
	fwrite(Ouf,1,p3-Ouf,stdout),fflush(stdout);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值