构造 取模技巧 1894 B. Two Out of Three

#include

using namespace std;

const int N=100+10;

int a[N];
int b[N];

void solve()
{
	int n;
	cin>>n;
	
	memset(b,1,sizeof b);
	
	for(int i=1;i<=n;i++)	cin>>a[i];
	
	int cnt=0;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(a[i]==a[j])	
				cnt++;
	
	if(cnt<=1)	cout<<-1<<endl;
	else
	{
		int k=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(a[i]==a[j]&&k<1)
				{
					b[i]=1;
					b[j]=2;
					k=1;
				}
				else if(a[i]==a[j]&&k>=1&&b[i]!=1)
				{
					b[i]=2;
					b[j]=3;
				}
			}
		}
		
		for(int i=1;i<=n;i++)	cout<<b[i]<<" ";
		cout<<endl;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

感觉思路非常清晰,但是样例都过不了,非常难受

思路是,首先计数,统计原来数组里面有多少个相同的元素,如果相同的元素的对数小于1,表示不可能找到满足条件的 b数组,直接输出-1即可

相同元素对数严格大于1的时候,一定可以构造出符合条件的b数组,此时让第一对相等的元素对应的b数组的值分别等于12,然后让之后相等的元素对应的b数组的值等于23

设置一个k,表示是第几对相等的元素

感觉之前的代码有点问题,增加了几个判断条件

#include

using namespace std;

const int N=100+10;

int a[N];
int b[N];

void solve()
{
	int n;
	cin>>n;
	
	memset(b,1,sizeof b);
	
	for(int i=1;i<=n;i++)	cin>>a[i];
	
	int cnt=0;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(a[i]==a[j])	
				cnt++;
	
	if(cnt<=1)	cout<<-1<<endl;
	else
	{
		int k=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(a[i]==a[j]&&k<1)
				{
					b[i]=1;
					b[j]=2;
					k=1;
				}
				else if(a[i]==a[j]&&k>=1&&b[i]!=1&&b[j]!=1&&b[j]!=2)
				{
					b[i]=2;
					b[j]=3;
				}
			}
		}
		
		for(int i=1;i<=n;i++)	cout<<b[i]<<" ";
		cout<<endl;
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

还是连样例都没有跑过去


#include

using namespace std;

void solve()
{
	int n;
	cin>>n;
	
	vector<int> a(n);
	map<int,int> mp;
	
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		mp[a[i]]++;
	}
	
	int cnt=0;
	for(auto [a,b]:mp)
		if(b>=2)
			cnt++;
	
	if(cnt<=1)
	{
		cout<<-1<<endl;
		return ;
	}
	
	vector<int> b(n);
	int x=1;
	for(int i=0;i<n;i++)
	{
		if(!b[i]&&mp[a[i]]>=2)
		{
			int col=0;
			for(int j=i;j<n;j++)
			{
				if(a[i]==a[j])
				{
					b[j]=col%2+x;
					col++;
				}
			}
			x++;
		}
		
		if(x==3)
			break;
	}
	
	for(int i=0;i<n;i++)
		if(!b[i])
			b[i]=1;
	
	for(auto e:b)
		cout<<e<<" ";
	cout<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

取模构造

发现是忽略了题目要求,满足且只满足其中两个条件,还是有一定难度的,很多东西我都没有考虑到

首先把相同的数字称作一类,至少要有两类以上才有可能满足题目要求

假设只有一类,一定难以恰好只满足两个条件,假设a数组是7 7 7,对应的b数组构造成1 2 3,同时满足三个条件,不行,b数组是1 1 2或者1 1 3或者2 2 3只满足一个条件,也不符合

所以只有一类或者一类都没有直接输出-1,表示不存在符合条件的b数组

然后是考虑大于两类,只用使得两类恰好符合两个条件即可,其他的所有位置全部填1即可(填2或者填3也行)

第一类满足第一个条件,第二类满足第三个条件(只要刚好满足两个条件就行),其他的类全填1,其他的不是类的也全部填1

取模可以保证该数字永远小于模的那个数字,严格小于,算是一个比较重要的技巧,col%2col0开始增大,可以使得变量一直在01之间波动,然后加上一个常数x,可以使得变量在xx+1波动,x设置为1,可以使得变量在12波动,形成的效果就是使得第一类12交替出现,满足条件1,然后把x增加1可以满足第三个条件(第二类),构造完两类,此时x=2,再增加一次就跳出循环即可

直接构造

还可以把每一类的第一个设置成1,第二个及以后的设置成2,满足第一个条件
第二类的第一个设置成2,第二个及以后的设置成3,满足第三个条件

构造方法如下

#include

using namespace std;

void solve()
{
	int n;
	cin>>n;
	
	vector<int> a(n);
	map<int,int> mp;
	
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
		mp[a[i]]++;
	}
	
	int cnt=0;
	for(auto [a,b]:mp)
		if(b>=2)
			cnt++;
	
	if(cnt<=1)
	{
		cout<<-1<<endl;
		return ;
	}
	
	vector<int> b(n);
	int x=2;
	int col=1;
	for(int i=0;i<n;i++)
	{
		if(!b[i]&&mp[a[i]]>=2)
		{
			b[i]=col;
			for(int j=i+1;j<n;j++)
				if(a[i]==a[j])
					b[j]=x;
			col++;
			x++;
		}
		
		if(x==4)
			break;
	}
	
	for(int i=0;i<n;i++)
		if(!b[i])
			b[i]=1;
	
	for(auto e:b)
		cout<<e<<" ";
	cout<<endl;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int t;
	cin>>t;
	
	while(t--)
		solve();
	
	return 0;
}

你可能感兴趣的:(#,CF,div,2,B,题,算法)