【洛谷7093】[CERC2014] Can't stop playing(搜索)
- 有一个初始为空的双端队列,你要插入\(n\)个\(2\)的非负整数幂,每次可以选择插入方向。
- 若相邻两个元素同为\(2^x\),则它们会发生合并变成\(2^{x+1}\)。
- 要求构造一组方案使得最终的队列里只有一个元素,或判断无解。
- \(n\le10^3,\sum a_i\le2^{13}\)
推结论+搜索
由于一个元素只可能不断变大,所以不可能出现一个数两边的数都比它大的情况,否则这个数一定无法被消去。
也就是说,无论何时,队列一定呈单峰形。
那么我们只要分别记录队列两部分的和,就知道了队列的构成,而且也方便了同类项的合并。
又由于在合并的过程中总和不变,所以我们只要记录一部分的和,用前面所有数的和减去它便得到了另一部分的和。
然后每次就只需讨论把当前元素放在哪一边,要求满足这一边为空或是这一边的最小值大于等于当前插入值。
代码:\(O(Tn\sum a_i)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define V 8192
using namespace std;
int n,a[N+5],s[N+5],h[V+5];char ans[N+5];
int vis[N+5][V+5];I bool dfs(CI x,CI p)//搜索
{
RI q=s[x-1]-p;if(x>n) return !q&&p==h[p]||!p&&q==h[q];//判断是否只有一个元素
if(vis[x][p]) return 0;RI P,Q,t;vis[x][p]=vis[x][q]=1;//记录已访问
if(h[P=p]>h[Q=q]&&(t=h[P],P-=t,Q+=t),(!P||(P&-P)>=a[x])&&(h[P+=a[x]]==h[Q]&&(P+=h[P]),dfs(x+1,P))) return ans[x]='l',1;//插左边
if(h[Q=q]>h[P=p]&&(t=h[Q],Q-=t,P+=t),(!Q||(Q&-Q)>=a[x])&&(h[Q+=a[x]]==h[P]&&(P+=h[P]),dfs(x+1,P))) return ans[x]='r',1;//插右边
return false;
}
int main()
{
RI Tt,i,j,t=1;W(t<=V) h[t]=t,t<<=1;for(i=1;i<=V;++i) !h[i]&&(h[i]=h[i-1]);//记录每个数最高位的值
scanf("%d",&Tt);W(Tt--)
{
for(scanf("%d",&n),i=1;i<=n;++i) for(scanf("%d",a+i),s[i]=s[i-1]+a[i],j=0;j<=s[i-1];++j) vis[i][j]=0;//清空数组
ans[n+1]=0,puts(dfs(1,0)?ans+1:"no");
}return 0;
}
待到再迷茫时回头望,所有脚印会发出光芒