【agc001d】Arrays and Palindrome

Portal -->agc001D

Description

  给你一个\(m\)个数的排列\(A\),这个\(A\)中元素的顺序可以随便调换,\(A\)中的元素的和为\(n\),现在要你构造一个数组\(B\)(长度为\(m1\)),满足:如果一个字符串同时满足:

1、头\(A_1\)个字符,接下来的\(A_2\)个字符,接下来的\(A_3\)个字符...接下来的\(A_m\)个字符分别构成回文串

2、头\(B_1\)个字符,接下来的\(B_2\)个字符,接下来的\(B_3\)个字符...接下来的\(B_{m1}\)个字符分别构成回文串

  那么这个字符串中每一个位置上的字符都一样

  

Solution

  日常不会构造题。。。qwq

  

  有一个比较好的想法就是。。画蚊香。。大概是这样:

o_agc019d.png

​  这个图对应的是\(A=\{3,2\}\)\(B=\{4,1\}\)

​  然后我们要做的就是。。使得连完线之后可以一笔画

​  然后发现如果说出现一个长度为奇数的回文串,最中间的那个点就会没有线连,然后为了让它和其他的点连上,这个点的度数必须是\(1\),然后为了保证一笔画,这样的点必须至多出现两个,所以奇数长度的回文串至多只能有两个,否则就无解了,然后多画几组会发现。。如果出现奇数长度的回文串它们还必须出现在一头一尾qwq

​  那么剩下的就是构造啦

  当全部都是偶数的时候,我们在最开头先放一个\(1\),这样后面就错开了,然后第\(1\)\(m-1\)都可以直接复制下来,至于最后一个回文串,我们可以放一堆\(2\)中间夹一个\(1\)这样(具体自己画一下就知道了)

  当有一个奇数的时候,我们把它放在\(A\)的最后,\(B\)的前面部分的构造方式同上,最后一个长度为奇数的回文串就简单一些,直接全部上\(2\)就好了

  当有两个奇数的时候,我们将其放在一头一尾,然后\(B\)的第一个元素设成\(A_1+1\),这样后面的情况就和只有一个奇数、并且已经放了一个\(1\)的情况一样了,剩下的构造同上

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e5+10;
int a[N],b[N*2],lis[3];
int n,m,cnt;
bool firstcheck(){
    int cnt=0;
    for (int i=1;i<=n;++i)
        cnt+=a[i]&1;
    return cnt<=2;
}
void get_b(){
    int sum;
    if (cnt==0){
        b[++b[0]]=1; sum=m-1;
        for (int i=1;i<n;++i) b[++b[0]]=a[i],sum-=a[i];
        if (sum==0) return;
        sum-=1; sum/=2;
        for (int i=1;i<=sum/2;++i) b[++b[0]]=2;
        b[++b[0]]=1;
        for (int i=sum/2+1;i<=sum;++i) b[++b[0]]=2;
    }
    else if (cnt==1){
        b[++b[0]]=1;
        for (int i=1;i<n;++i) b[++b[0]]=a[i];
        for (int i=1;i<=(a[n]-1)/2;++i) b[++b[0]]=2;
    }
    else{
        b[++b[0]]=a[1]+1;
        for (int i=2;i<n;++i) b[++b[0]]=a[i];
        for (int i=1;i<=(a[n]-1)/2;++i) b[++b[0]]=2;
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    scanf("%d%d",&m,&n);
    for (int i=1;i<=n;++i) scanf("%d",a+i);
    if (!firstcheck()){printf("Impossible\n"); return 0;}
    cnt=0;
    for (int i=1;i<=n;++i){
        if ((a[i]&1)) 
            lis[++cnt]=i;
    }
    if (lis[1]) swap(a[n],a[lis[1]]);
    if (lis[2]) swap(a[1],a[lis[2]]);
    for (int i=1;i<=n;++i) printf("%d ",a[i]); printf("\n");

    get_b();
    printf("%d\n",b[0]);
    for (int i=1;i<=b[0];++i) printf("%d ",b[i]); printf("\n");
}

转载于:https://www.cnblogs.com/yoyoball/p/9860401.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值