[AT1982] [AGC001 D] Arrays and Palindrome

26 篇文章 0 订阅
19 篇文章 0 订阅
洛谷传送门
Atcoder传送门

题目大意

给你一个所有元素为正整数且和为 N N N,长度为 M M M的序列 A A A, 要你求出 A A A的一个排列 A ′ A' A和一个所有元素为正整数且和为 N N N的序列 B B B, 满足符合前 A 1 ′ A'_1 A1个字符, 之后的 A 2 ′ A'_2 A2个字符…组成的都是回文串,前 B 1 B_1 B1个字符, 之后的 B 2 B_2 B2个字符…组成的都是回文串, 且这样的字符串只可能由一种字符构成。

输入输出格式

输入格式

第一行两个正整数 N , M N,M N,M

第二行 M M M个元素分别代表 A 1 , A 2 , . . . , A M A_1,A_2,...,A_M A1,A2,...,AM

输出格式

第一行 M M M个正整数分别表示 A 1 ′ , A 2 ′ , . . . , A M ′ A'_1,A'_2,...,A'_M A1,A2,...,AM

第二行一个正整数 K K K表示序列 B B B的长度。

第三行 K K K个正整数分别表示 B 1 , B 2 , . . . , B K B_1,B_2,...,B_K B1,B2,...,BK

输入输出样例

输入样例#1:
3 2
2 1
输出样例#1:
1 2
1
3
输入样例#2:
6 1
6
输出样例#2:
6
3
1 2 3
输入样例#3:
55 10
1 2 3 4 5 6 7 8 9 10
输出样例#3:
Impossible

解题分析

很容易得到一个图论模型: 把对称的点连起来, 如果最终连通块只有一个那么就是正确的。

这样做以后发现最多只有两个长度为奇数的回文串限制(否则最终连的边数不够 N − 1 N-1 N1条)。

那么就好办了, 直接搞错开一格就可以连上不同连通块了。

注意特判一堆情况。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#include <vector>
#define R register
#define IN inline
#define gc getchar()
#define ll long long
#define MX 105
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
int n, sum;
std::vector <int> eve, odd;
int main(void)
{
	in(sum), in(n);
	int foo;
	for (R int i = 1; i <= n; ++i)
	{
		in(foo);
		if (foo & 1) odd.push_back(foo);
		else eve.push_back(foo);
	}
	if (n == 1)
	{
		if (sum == 1) printf("1\n1\n1");
		else printf("%d\n2\n%d %d", sum, 1, sum - 1);
		return 0;
	}
	if (odd.size() > 2) return puts("Impossible"), 0;
	else if (odd.size() == 2)
	{
		if (odd[0] > odd[1]) std::swap(odd[0], odd[1]);
		printf("%d ", odd[0]);
		for (auto i : eve) printf("%d ", i);
		printf("%d\n", odd[1]);
		odd[0]--, odd[1]++;
		if (!odd[0]) printf("%d\n", n - 1);
		else printf("%d\n%d ", n, odd[0]);
		for (auto i : eve) printf("%d ", i);
		printf("%d ", odd[1]);
	}
	else if (odd.size() == 1)
	{
		printf("%d ", odd[0]);
		for (auto i : eve) printf("%d ", i);
		puts("");
		odd[0]++, eve[eve.size() - 1]--;
		printf("%d\n", n);
		printf("%d ", odd[0]);
		for (auto i : eve) printf("%d ", i);
	}
	else
	{
		for (auto i : eve) printf("%d ", i);
		eve[0]++, eve[eve.size() - 1]--;
		printf("\n%d\n", n);
		for (auto i : eve) printf("%d ", i);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值