[AGC001 D]Arrays and Palindrome

题意

对于一对数组\(a_i\)\(b_i\),满足\(\sum\limits_{i=1}^{k_a}a_i=\sum\limits_{i=1}^{k_b}b_i=N\),而且对于所有长度为\(N\)的字符串,如果在满足下列两个条件的前提下:

  • 对于前\(a_1\)个,接下来\(a_2\)个,再接下去\(a_3\)个……都是回文串

  • 对于前\(b_1\)个,接下来\(b_2\)个,再接下去\(b_3\)个……都是回文串

同时还必然满足这个字符串一定全部字符都一样。如果只有原来\(a_i\)的一个排列,求一种这个\(a_i\)数组和相应的\(b_i\)数组。注意可能不存在。

  • \(N\leq 10^5\)
  • \(k_a \leq 100\)
  • \(A_i\leq 10^5\)

分析

先考虑\(k_a\)比较小的情况,例如\(k_a=1\),这个时候可以发现我们只需要让回文串错一位就可以了。

对于\(k_a=2\),考虑我们从那个中间分隔的点开始往外直接扩展,实际上只要覆盖到两边回文串中间的那个点,然后剩下来的直接随便覆盖就可以了(因为就这一些已经将两个回文串“连接”在了一起),这是一个思路,但是比较难以实现。

更加直接的思路(按照题解),还是按照错位,我们考虑实际上只需要将中间那个分割点向左边移动一下,那也是能够相应建立关系的。

按照这个思路,我们应该可以进一步地考虑推广!我们应该可以按照这个思路,只需要取\(b=\{a_1-1,a_2,\cdots,a_{k_a-1},a_{k_a}+1\}\),这种答案的构造方法,除非是中间的数是偶数,否则都是可以的。

那么当存在大量偶数的时候有没有可能构造出一个相应的解呢?我们考虑设\(a\)里面偶数有\(O_a\)个,\(b\)里面偶数有\(O_b\)个,那么边数是\(\frac{N-O_a}{2}+\frac{N-O_b}{2}\),考虑如果我们要让这\(N\)个点连通,我们肯定至少需要\(N-1\)条边,那么也就是\(\frac{N-O_a}{2}+\frac{N-O_b}{2}\geq N-1\),这个不等式算出来是\(O_a+O_b\leq 2\)……于是我们发现不可能偶数多于\(2\)个。如果满足的话那一定可以将这两个偶数调到最前和最后。

那么我们只要扫一遍就可以得到了。回顾一下思路,我们从\(k_a=1\)的情况推出了错位的思路,然后进一步推广到了一般情况,同时对于一种看上去比较特殊的情况得出了解。最后,我们证明了剩下的情况没有解,实际上也就是说因为有偶数,所以相当于要浪费一部分边去专门将偶数导走,然后整个图就无法导通。

注意在写的时候有可能会出现减出\(0\)的情况,所以需要再判一下边界情况。

# include <bits/stdc++.h>
# define il inline
# define fi first
# define se second
# define pb push_back
# define mem(x,v) memset(x,v,sizeof x)
# define rep(i,x,y) for(int i=x;i<=y;++i)
# define re(i,x,y) for (int i=x;i<y;++i)
using namespace std;
typedef long long ll;
il ll read(){
    ll x=0; char c=getchar();
    for(;c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
    return x;
}
const int maxm = 100+10;
int n,m;
int a[maxm];
vector<int> b;
int main(){
    n=read(); m=read();
    rep(i,1,m) a[i]=read();
    if (m == 1){
        b.pb(1); b.pb(n-1);
    }
    else{
        int cnt = 0;
        rep(i,1,m) cnt += a[i] % 2;
        if (cnt > 2){
            puts("Impossible"); return 0;
        }
        rep(i,2,m-1)
            if (a[i]%2==1){
                if (a[1]%2==0)swap(a[1],a[i]);
                else swap(a[m],a[i]);
            }
        b.pb(a[m]+1);
        for (int i=m-1;i>1;--i) b.pb(a[i]);
        b.pb(a[1]-1);
    }
    rep(i,1,m) printf("%d ",a[i]); printf("\n");
    int bs=b.size();
    if (b[bs-1] == 0)--bs;
    printf("%d\n",bs);
    for (int i=bs-1;i>=0;--i) printf("%d ",b[i]); printf("\n");
    return 0;
}

转载于:https://www.cnblogs.com/wendavid/p/8982266.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值