原题目资料连接:Link

首先合并肯定是越合越大的,又我们在两头加数,所以一个可行的队列总是单峰的。

形式话的说:

$a_1 < a_2 < \dots < a_K$

$a_K > a_{K-1} > \dots > a_n$

那么我们考虑如何表示它。

对于序列的左边,注意到它是递增的,再根据相同项合并的规则,以及 $a_i = 2^p$,我们会发现它是序列总和的二进制拆分。

更具体的,其类似于 2 8 16 32 的形式。

对于序列的右边也是这样的。

而总和是我们知道的,所以我们只需要左边序列的和即可表示这样一个单峰的合法序列。

故可以动态规划,设 $f(i,s)$ 表示考虑到第 $i$ 位,左侧序列为 $s$ 是否可以被操作构造出来。

那么我们每次加入一个数 $a_i$,其能加入左侧序列 $s$ 当且仅当满足下列两个条件之一($\operatorname{lowbit}$ 表示二进制最低位):

  • $s = 0$
  • $a_i \leq \operatorname{lowbit}(s)$

对于右侧序列 $(\sum_{j=1}^i a_i) - s$ 同理。

通过上述方式转移完之后,我们还需要判断一些情况。

首先对于“峰”即上文所说 $a_K$ 其可以属于左或右两边,需要处理。

同时两边序列的最高点有可能相同,我们需要判断然后合并。

答案 $f(n,\sum a)$。

对于”峰“,实现中我们可以预处理一个数的二进制最高位来解决。

同时还需要记录转移点和插入在左还是右两个信息,方便最后用递归找答案。

记得判断 $\sum a_i$ 是否是 $2$ 的幂。

时间复杂度 $O(n \sum a_i)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3;
const int maxs=1<<13;
int n;
int a[maxn+5],sum;
bool f[maxn+5][maxs+5];
char g[maxn+5][maxs+5];
int to[maxn+5][maxs+5];
int h[maxs+5];
char str[maxn+5];
inline int Lowbit(int x){return x&(-x);}
inline bool Check(int x,int s){
return (s==0)||(x<=Lowbit(s));
}
void Print(int i,int s){
if(i){
if(g[i][s]) str[i]=g[i][s],Print(i-1,to[i][s]);
else str[i]=g[i][s],Print(i-1,to[i][s]);
}
}
inline void Solve(){
scanf("%d",&n);
sum=0;
f[0][0]=1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum+=a[i];
for(int s=0;s<=sum;s++) f[i][s]=0;
}
sum=0;
for(int i=1;i<=n;i++){
for(int s=0;s<=sum;s++){
if(!f[i-1][s]) continue;
if(Check(a[i],s)){
f[i][s+a[i]]=1;
g[i][s+a[i]]='l';
to[i][s+a[i]]=s;
}
if(Check(a[i],sum-s)){
f[i][s]=1;
g[i][s]='r';
to[i][s]=s;
}
}
sum+=a[i];
for(int s=0;s<=sum;s++){
if(!f[i][s]) continue;
if(h[s]<h[sum-s]){
f[i][s+h[sum-s]]=1;
g[i][s+h[sum-s]]=g[i][s];
to[i][s+h[sum-s]]=to[i][s];
}
if(h[s]>h[sum-s]){
f[i][s-h[s]]=1;
g[i][s-h[s]]=g[i][s];
to[i][s-h[s]]=to[i][s];
}
if(h[s]==h[sum-s]){
f[i][s]=0;
f[i][s+h[s]]=1;
f[i][s-h[s]]=1;
g[i][s+h[s]]=g[i][s];
g[i][s-h[s]]=g[i][s];
to[i][s+h[s]]=to[i][s];
to[i][s-h[s]]=to[i][s];
}
}
}
int tmp;for(tmp=sum;!(tmp&1);tmp>>=1);
if(tmp==1&&f[n][sum]){
Print(n,sum);
for(int i=1;i<=n;i++) putchar(str[i]);
putchar('\n');
}
else puts("no");
}
inline void Init(){
for(int s=0;s<=maxs;s++){
if(Lowbit(s)==s) h[s]=s;
else h[s]=h[s>>1]<<1;
}
}
signed main(){
Init();
int T;scanf("%d",&T);
while(T--) Solve();
return 0;
}