1. 程式人生 > 其它 >P1087 [NOIP2004 普及組] FBI 樹

P1087 [NOIP2004 普及組] FBI 樹

思路:由於遞迴每一層都計數[l, r]中1和0的個數複雜度太高,極限情況下,遞迴過程中計數的複雜度:\(1024^{11} = 2^{110}\),這裡用字首和記錄一下1的個數,就可以每一層\(O(1)\)複雜度獲得1的個數了,做法就是根據題目說的遞迴構造樹,然後後續遍歷

空間大小問題:題目中最長序列為\(2^{10}\),則二叉樹最多11層,則總結點數為\(2^{11} - 1\)

#include<iostream>
#include<string>

using namespace std;

const int N = 2500, M = 1500;

struct node{
    int l, r;
    char val;
}tr[N];

int idx;

// 2^(l - 1) = 2^N => l = N + 1

int n;
int a[M];
char s[N];

void dfs(int l, int r, int u){
    if(l == r){
        if(s[l] == '0') tr[u].val = 'B';
        else tr[u].val = 'I';
        tr[u].l = tr[u].r = -1;
        return;
    } 
    
    tr[u].l = ++ idx, tr[u].r = ++ idx;
    
    int ones = a[r] - a[l - 1];
    if(ones == r - l + 1) tr[u].val = 'I';
    else if(ones == 0) tr[u].val = 'B';
    else tr[u].val = 'F';
    
    int mid = l + r >> 1;
    dfs(l, mid, tr[u].l), dfs(mid + 1, r, tr[u].r);
}

void trav(int u){
    if(u == -1) return;
    trav(tr[u].l), trav(tr[u].r);
    cout << tr[u].val;
}

int main(){
    cin >> n;
    
    for(int i = 1; i <= 1 << n; i ++) cin >> s[i];
    for(int i = 1; i <= 1 << n; i ++)
        a[i] = a[i - 1] + (s[i] == '1');
    
    dfs(1, 1 << n, 0);
    trav(0);
    
    return 0;
}