• 【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

      

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

    ​  这个图对应的是(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
    "); 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("
    ");
    
    	get_b();
    	printf("%d
    ",b[0]);
    	for (int i=1;i<=b[0];++i) printf("%d ",b[i]); printf("
    ");
    }
    
  • 相关阅读:
    假设用一个名为text的字符串向量存放文本文件的数据,其中的元素或者是一句话或者是一个用于表示段分隔的空字符串。将text中第一段全改为大写形式
    迭代器介绍
    从cin读入一组词并把它们存入一个vector对象,然后设法把所有词都改写为大写字母。
    标准库类型vector
    css 滤镜之AlphaImageLoader
    css设置背景图片自适应
    网易云音乐怎么免费下载付费歌曲
    font-family,font-size,color
    css设置图片居中、居左、居右
    数据库语句之建表、拷贝数据表
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9860401.html
Copyright © 2020-2023  润新知