P7093 [CERC2014]Can't stop playing (动态规划)

题意:

戳这里

分析:

DP

来贡献一发最劣解的做法

  • 暴力

我们发现由于长度之和不超过\(2^{13}\) ,所以放进去的块可以用一个不超过 \(2^{14}\) 的数字状压出来,其次我们手玩样例会发现一个性质,就是过程中拼出来的序列满足大小形状类倒着的 V

证明:

若存在 \(a>b<c\) ,那么 \(b\) 没有办法和任何一个块消掉

所以我们把序列拆成左右两个单调的序列,然后每次判断一下能不能并到左边或者右边,只要满足以下任何一个条件即可:

  1. 左序列或者右序列为空
  2. 小于左序列或者右序列的最小值

然后我们就得到了一个 \(O(tn2^{26}\times13)\) 的做法

  • 优化

我们发现左右序列的和值固定,所以只需要枚举左序列的状态就可以了,复杂度降低为 \(O(tn2^{13}\times 13)\) ,但是由于直接枚举是跑满的,所以会 TLE

  • 正解

我们发现状态转移是固定的,所以不需要枚举状态,直接 DFS 就可以了,并且预处理一下 highbit ,复杂度就变成了常数极小的 \(O(n2^{13})\)

tip:

  1. 可能存在一种情况就是,左右序列都单调递增,所以转移的时候每次记得把左右序列相连的部分能合并就合并,不然会像我一样直接白给好多发

    比如 2|2 的情况添加一个 4,原本是添加不进去的,但先合并之后变成 4|0,然后就可以添加进去了

  2. 记忆化一下,保证复杂度正确

代码:

#include<bits/stdc++.h>
#define inl inline
#define reg register
#define mk(x,y) make_pair(x,y)
#define fir first
#define sec second

using namespace std;

namespace zzc
{
    typedef long long ll;
    inl ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const ll maxn = 1005;
    const ll maxm = (1<<14);
    ll n,t;
    bool vis[maxn][maxm],ans[maxn];
    ll sum[maxn],a[maxn],hig[maxm];

    inl ll merge(ll x,ll y,ll k)//表示将 k 加到 x 序列上 
    {
        if(hig[x]>hig[y])//先将x序列最大值并到y序列上, 参考 tip:1 
        {
        	ll tmp=hig[x];
        	x-=tmp;
        	y+=tmp;
        }
        if(x&&(x&(-x))<k) return -1;x+=k;
        if(hig[x]==hig[y])//合并两个序列相连的部分 
        {
        	ll tmp=hig[x];
        	x+=tmp;
        	y-=tmp;
        }
        return x;
    }
    
	bool dfs(ll pos,ll lef)
	{
		ll rig,now;
		rig=sum[pos]-lef;
        if(pos==n)
        {
        	//将左右序列合并化到最简 
        	lef=merge(lef,rig,0);
        	rig=sum[pos]-lef;
        	if(lef==sum[n]&&(lef&(lef&(-lef)))==lef) return true;
        	if(rig==sum[n]&&(rig&(rig&(-rig)))==rig) return true;
        	return false;
        }
        if(vis[pos][lef]) return false;
        vis[pos][lef]=true;
        
        now=merge(lef,rig,a[pos+1]);
        if(now!=-1&&dfs(pos+1,now)) 
        {
            ans[pos+1]=true;
            return true;
        }
        
        now=merge(rig,lef,a[pos+1]);
        if(now!=-1&&dfs(pos+1,sum[pos+1]-now))
        {
            ans[pos+1]=false;
           	return true;
        }
        
        return false;
	}
	
	void init()
	{
		for(reg ll i=1;i<(1<<14);i++)// 预处理 highbit 
		{
			if((i&(-i))==i) hig[i]=i;
			else hig[i]=hig[i-1];
		}
	}
	
    void work()
    {
    	init();
        t=read();
        while(t--)
        {
    	     memset(vis,false,sizeof(vis));
             memset(ans,false,sizeof(ans));
             n=read();
             for(reg ll i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
             if(!dfs(0,0)) printf("no");
             else for(reg ll i=1;i<=n;i++) printf("%c",(ans[i]?'l':'r'));
             puts("");
        }
    }

}

int main()
{
    zzc::work();
    return 0;
}
posted @ 2021-02-04 18:01  youth518  阅读(121)  评论(0)    收藏  举报