题目大意
给定一个元素和为$N$的有$M$个数的序列$A$,请你可以$A$元素排列的顺序,并需要构造一个有$K$个($K$可以自己定)数的数列,使得任意一个长度为$N$的字符串,若满足:前$A_1$字符是回文串,接下来$A_2$个字符是回文串,直到$最后A_M$个字符也是一个回文串,且对于$B$同样满足这个性质,则这个字符串一定只能由一种字符构成。
题解
考虑一个回文串实际是在每一对关于中心对称的两个位置之间连一条边,那么原题就变成了连边让所有位置连成一个连通块。
显然我们至少需要$n-1$条边,那么对于每一个$A_i$,它提供的边数是$lfloorfrac{A_i}{n} floor$,考虑到$sum(A_i+B_i)=N$,那么$A_i,B_i$最多出现两个奇数,否则无解。
考虑$A_1$和$B_1$左对齐,我们只需要让$B_i=A_ipm 1$,那么$B_i,A_i$这些位置就会被连城一个连通块。
考虑$A_i=B_i$但$B_i$相互错位了一个位置,画图发现当且仅当$A_i$是偶数时,这$A_i+1$个位置就能连成一个连通块。
由于奇数的情况不超过两个,那么可以直接把奇数放在两边,然后把$A$复制下来,最左边的数$-1$,最右边的数$+1$,把$0$过滤掉输出即可。
注意要特判$n,m=1$之类的情况
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 120 using namespace std; namespace IO{ const int BS=(1<<20)+5; int Top=0; char Buffer[BS],OT[BS],*OS=OT,*HD,*TL,SS[20]; const char *fin=OT+BS-1; char Getchar(){if(HD==TL){TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);} return (HD==TL)?EOF:*HD++;} void flush(){fwrite(OT,1,OS-OT,stdout);} void Putchar(char c){*OS++ =c;if(OS==fin)flush(),OS=OT;} void write(int x){ if(!x){Putchar('0');return;} if(x<0) x=-x,Putchar('-'); while(x) SS[++Top]=x%10,x/=10; while(Top) Putchar(SS[Top]+'0'),--Top; } int read(){ int nm=0,fh=1; char cw=Getchar(); for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0'); return nm*fh; } } using namespace IO; int n,m,p[M],tg,ct,tot,t[M]; int main(){ n=read(),m=read(); for(int i=1;i<=m;i++) p[i]=read(),ct+=(p[i]&1); if(ct>2){puts("Impossible");return 0;} for(int i=2;i<=m;i++){ if(!(p[i]&1)) continue; if(!(p[1]&1)) swap(p[1],p[i]); else swap(p[m],p[i]); } if(n==1){puts("1 1 1 ");return 0;} if(m==1){printf("%d 2 %d %d ",p[1],1,p[1]-1);return 0;} if(p[1]>1) t[tot=1]=p[1]-1; for(int i=2;i<=m;i++) t[++tot]=p[i]; t[tot]++; for(int i=1;i<=m;i++) printf("%d%c",p[i],i<m?' ':' '); printf("%d ",tot); for(int i=1;i<=tot;i++) printf("%d%c",t[i],i<tot?' ':' '); return 0; }