题意:一维2048。对于当前序列,只能把当前的数字放在最左边或者最右边,相邻两个数字如果相同会融合。问能否通过贪心操作使得最后序列只有一个元素。
思路:
首先,要构造的序列一定是一个’ ^ ‘形的,因为一旦是’ v ‘形,处于低谷的那个小数字永远不可能被消除。
那么可以把构造出来的序列拆分成左右两部分,使得左半部分呈上升趋势,右半部分呈下降趋势。
由于所有值都是二的倍数,左半部分可以用一个数字直接表示出来。
比如: 左序列 1 2 4 8 可以直接用数字15表示,而数字15能且只能表示序列1 2 4 8 。
这里只讨论左半部分,右半部分其实是一样的,不再赘述。
那么,采取搜索的方式,假设选到第pos个数字时,左半序列和为lsum;
对于第pos个数字(假设为a[pos]),如果a[pos]想插在左边
(1)满足:a[pos]不大于左半序列的最小数字。
所以我们求出lsum的lowbit值,就可以知道a[pos]可不可以放在左半序列。(注意这里,如果lowbit为0,应该改为把0改为inf)
如果a[pos]可以放在左边,我们继续记忆化搜索:dfs(pos+1,lsum+a[pos]);
(2)满需:左半序列可以直接和右半序列合并,相当于把左半序列移到右边去;
如果能把左边的序列全都移到右边去,我们也能继续搜索。
至于highBit,意义和lowbit是相反的,用于记录lsum最大的那个数字是多少。
右边同理。
#pragma comment(linker, "/STACK:102400000,102400000")
#include<bits/stdc++.h>
using namespace std;
#define maxn 1024
char ans[maxn];
int n;
int sum[maxn];
bool vis[maxn][(1<<13)+5];
int highbit[1<<14];
int a[1024];
int getlowbit(int val){
for(int i=0;i<14;i++){
if(val&(1<<i))
return (1<<i);
}return (1<<14);
}
bool dfs(int pos,int lsum){
bool ret=0;
int rsum = sum[pos-1]-lsum;
if(pos>n){
if(lsum==highbit[lsum]&&rsum==highbit[rsum]&&lsum+rsum==highbit[lsum+rsum]){
return true;
}return false;
}
if(vis[pos][lsum]||vis[pos][rsum])return false;
vis[pos][lsum]=vis[pos][rsum]=true;
int lowbitL = getlowbit(lsum);
int lowbitR = getlowbit(rsum);
if(a[pos]<=lowbitL){
int L=lsum + a[pos], R=rsum;
if(highbit[L]==highbit[R]){
L+=highbit[L];
R-=highbit[R];
}
if(dfs(pos+1,L)){
ans[pos-1]='l';ret=1;
}
}
else if(rsum==highbit[rsum]&&rsum>=highbit[lsum]){
int L=lsum+rsum, R=a[pos];
if(highbit[L]==highbit[R]){
L+=highbit[L];
R-=highbit[R];
}
if(dfs(pos+1,L)){
ans[pos-1]='r';ret=1;
}
}
if(a[pos]<=lowbitR){
int L=lsum, R=rsum + a[pos];
if(highbit[L]==highbit[R]){
L+=highbit[L];
R-=highbit[R];
}
if(dfs(pos+1,L)){
ans[pos-1]='r';ret=1;
}
}
else if(lsum==highbit[lsum]&&lsum>=highbit[rsum]){
int L=a[pos], R=lsum+rsum;
if(highbit[L]==highbit[R]){
L+=highbit[L];
R-=highbit[R];
}
if(dfs(pos+1,L)){
ans[pos-1]='l';ret=1;
}
}
return ret;
}
int main(){
for(int i=1;i<(1<<14);i++){
if((i&-i)==i)highbit[i]=i;
else highbit[i]=highbit[i-1];
}
int t;cin>>t;
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
sum[i]=sum[i-1]+a[i];
memset(vis[i],0,sizeof(vis[i]));
}
if(dfs(1,0)){
ans[n]='\0';
printf("%s\n",ans);
}
else{
puts("no");
}
}
return 0;
}