POJ 2161 Chandelier(树状DP)

一、题意

首先是对题目的翻译。给出一个长长的字符串,这个字符串描述了一个吊灯。对于给字符串只有两种操作数——'a'为一个吊灯灯珠,将改灯珠入栈,一位阿拉伯数字K,代表一个环,将把该数字前面k位数都出栈并且穿成一个环,并将该环重新入栈(作为一个单元)。由此可以得到一颗神奇的树——每个节点的若干子节点呈现循环数组的关系。因而此处有对于同构的定义为:再该环上各个小串的相对位置不变。于是,要求一个新的字符串,能够成上述字符转的一个同构的树,在这个基础上求出最小的“最大栈空间”大小。

二、思路

首先设dp[i]为将第i个节点及其子树全部入栈的最小栈大小。对于其第一个入栈的子树,认为此时的最高栈高度为k,则dp[i]=main(dp[i],dp[tar]+i)。此时应当枚举起点并且找到使得值最小的起点。

(红书说是使用单调栈实现O(N)的求出这个值得具体大小,但是经过隔壁队YC大佬指点发现不是单调栈而是一个简单思路(复杂度O(n))对于每个起点的特定顺序,必然有,最大值为上一个的最大值-1,或者上一个的起点+m-1。于是这样就可以O(1)的找出每一组的最大值,直接对比就好)

//#include<bits/stdc++.h>
#include<vector>
#include<stack>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
#define veci vector<int>
#define stai stack<int>

const long long MAXN=1e4+233;
veci G[MAXN];
stai ss;
char str[MAXN];
int length;
int dp[MAXN];
int pos[MAXN];

int deal(int now)
{
    int len=G[now].size();
    int maxx=dp[G[now][0]];
    for(int i=0;i<len;++i)
    {
        maxx=max(maxx,dp[G[now][i]]+i);
    }
    int ans=maxx;
    for(int i=1;i<len;++i)
    {
        maxx=max(maxx-1,dp[G[now][i-1]]+len-1);
        if(ans>maxx)
        {
            pos[now]=i;
            ans=maxx;
        }
    }
    return ans;
}

void dfs(int now)
{
    int len=G[now].size();
    if(len==0)
    {
        dp[now]=1;return ;
    }
    for(int i=0;i<len;++i)
    {
        int tar=G[now][i];
        dfs(tar);
    }
    dp[now]=deal(now);
}

void show(int now)
{
    int len=G[now].size();
    if(len==0)
    {
        cout<<"a";return ;
    }
    for(int i=0;i<len;++i)
    {
        int pp=pos[now]+i;
        pp%=len;
        int tar=G[now][pp];
        show(tar);
    }
    cout<<G[now].size();
}

void init()
{
//    gets(str+1);
    length=strlen(str+1);
    memset(dp,0,sizeof(dp));
    memset(pos,0,sizeof(pos));
    int ll=0;
    for(int i=1;i<=length;++i)
    {    
        
        G[i].clear();
            ll=max(ll,(int)ss.size());
        if(str[i]!='a')
        {
            int len=str[i]-'0';
            stai s2;
            for(int j=0;j<len;++j)
            {
//                int tar=ss.top();
                s2.push(ss.top());
                ss.pop();
//                G[i].push_front(tar);
//                G[i].push_back(tar);
            }
            while(!s2.empty())
            {
                G[i].push_back(s2.top());
                s2.pop();
            }
        
        }    ss.push(i);
    }
    dfs(length);
    cout<<dp[length]<<"\n";
    show(length);
    cout<<"\n";
//    cout<<endl<<ll<<endl;
    
}


int main()
{
    cin.sync_with_stdio(false);
    while(cin>>(str+1))init();
    
    return 0;
}

 

posted @ 2017-11-10 13:48  六花的邪王真眼  阅读(249)  评论(0编辑  收藏  举报