[AGC001D] Arrays and Palindrome 题解

发布时间 2023-10-12 15:25:44作者: _hjy

非常有意思的思维题。

首先我先瑞平一下翻译,我根本没看懂,还是去看英文题面看懂的。

首先可以发现整个字符串被拆成了若干个奇回文串与偶回文串。现考虑如何判是否合法。可以发现一个回文串就是要求部分位置匹配。我们对这些匹配的位置建边,如果得到的图是联通的,那么就只能填入 \(1\) 种字符,否则就可以填入多种字符。

然后考虑构造一个解。容易想到奇回文串与偶回文串区别是相当大的。对于一个长度为 \(k\) 偶回文串,我们可在它的前面错位的放一个长度为 \(k\) 的偶回文串,这样它内部是联通的,同时也与前面联通,后面还空出来一个点,可以让后面的往前接上他。

对于一个奇回文串,我们可以发现这样的构造只适用于头和尾,不过我们幸好可以证明对于大于等于 \(3\) 个奇回文串,没有构造方案。

\(N\) 为偶数时,总共需要 \(N-1\) 条边使得整张图联通,而序列 \(B\) 可以为我们提供 \(\frac{N}{2}\) 条边,由于上面有大于等于 \(3\) 个奇回文串,因此至多有 $ \lfloor \frac{N-3}{2} \rfloor \leq \frac{N}{2}-2$ 条边,因此整张图必定不联通。

对于 \(N\) 为奇数有类似的证明。

注意特殊处理第 \(1\) 个与最后一个,还有只有 \(1\) 个的情况。

code:

#include<iostream>
using namespace std;
const int MX=1e5+7;
int a[MX],A[MX],B[MX];
int main(){
	int n,m,cnt=0;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i];
		if(a[i]&1)cnt++;
	}
	if(cnt>=3){
		cout<<"Impossible"<<endl;
		return 0;
	}
	int l=1,r=n;
	for(int i=1;i<=m;i++)
		if(a[i]&1){
			if(l==1){
				l++;
				A[1]=a[i];
			}
			else{
				r--;
				A[m]=a[i];
			}
		}
	for(int i=1;i<=m;i++)
		if(!(a[i]&1))A[l++]=a[i];
	int tot=0;
	if(m!=1){
		for(int i=1;i<=m;i++){
			if((A[i]&1)){
				if((A[i]-1+(i==m?2:0)!=0))B[++tot]=A[i]-1+(i==m?2:0);
			}
			else{
				if(A[i]-(i==1?1:0)!=0)B[++tot]=A[i]-(i==1?1:0);
				if(i==m)B[++tot]=1;
			}
		}
	}
	else{
		if(A[1]!=1)B[++tot]=A[1]-1;
		B[++tot]=1;
	}
	for(int i=1;i<=m;i++)cout<<A[i]<<' ';
	cout<<endl;
	cout<<tot<<endl;
	for(int i=1;i<=tot;i++)cout<<B[i]<<' ';
	cout<<endl;
	return 0;
}