AT1982 [AGC001D] Arrays and Palindrome 题解

Description

Luogu传送门

简单说一下题意吧。

就是输入一个长度为 \(m\),元素和为 \(n\) 的序列 \(a\)\(a\) 数组的定义就是题面中的含义。

你需要构造出一个 \(b\) 序列,同样也表示回文串的长度,使得只有全 1 的序列满足 \(a\)\(b\) 这两个条件。

Solution

emm……看了 \(n\) 分钟没看懂题,然后 xrf 学长题都讲完了,听了个大概但还是不懂题,跑去找 xrf 学长帮我解释,又解释了 \(n\) 分钟才懂……

菜的真实。

“接口”,以及是奇数的 \(a_i\) 不得超过两个且必须在两边什么的可以直接去看第一篇题解,非常清晰 CCCCCOrz

这里讲一下构造方法。

经过无数次尝试,发现这样构造是可以的。

样例:

14 4
2 3 4 5

首先排完序之后,奇数被放到了两边(偶数随便排),即:

3 2 4 5

我们画个图构造一下:

image

蓝色的就是构造出的 \(b\) 序列,即:

4 2 4 4

不难发现

\(b_1 = a_1 + 1\)

\(b_4 = a_4 - 1\)

多试几组样例发现这样构造确实是可以的(证明去看各位大佬的题解吧QwQ)

注意:

  1. 如果 \(a_m = 1\),那么最后一位直接删去即可。
  2. \(m = 1\) 时要特判,具体见代码。
  3. \(a_i\) 是奇数的数的个数大于 2 时,直接输出 Impossible

Code

#include <bits/stdc++.h>

using namespace std;

namespace IO{
    inline int read(){
        int x = 0, f = 1;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x * f;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }

    inline void print(int a[], int m){
        write(a[1]), putchar(' ');
        for(int i = 3; i <= m; ++i) write(a[i]), putchar(' ');
        if(a[2]) write(a[2]), puts("");
    }
}
using namespace IO;

const int N = 1e5 + 10;
int n, m, cnt;
int a[N], b[N];

inline bool cmp(int a, int b){
    return (a & 1) > (b & 1);
}

int main(){
    n = read(), m = read();
    for(int i = 1; i <= m; ++i) a[i] = read(), cnt += (a[i] & 1);
    if(cnt > 2) return puts("Impossible"), 0;
    if(m == 1){
        if(a[1] == 1) printf("1\n1\n1\n");
        else printf("%d\n2\n1 %d\n", a[1], a[1] - 1);
        return 0;
    }
    sort(a + 1, a + 1 + m, cmp);
    print(a, m);
    write(m - (a[2] == 1)), puts("");
    a[1]++, a[2]--;
    print(a, m);
    return 0;
}

\[\_EOF\_ \]

原文地址:https://www.cnblogs.com/xixike/p/15690330.html