BSG挑戰賽

A/C

模擬題,較簡單

B-AVL樹的種類

平衡二叉樹(AVL樹),是指左右子樹高度差至多爲1的二叉樹,並且該樹的左右兩個子樹也均爲AVL樹。 現在問題來了,給定AVL樹的節點個數n,求有多少種形態的AVL樹恰好有n個節點。

DP
定義 f[i][j] 爲含有 i 個節點高度爲 j 的平衡樹的數量,轉移方程就很好寫了:
if(k > 0) add(f[i][k+1], f[j][k] * f[s-j][k-1] % MOD);
add(f[i][k+1], f[j][k] * f[s-j][k] % MOD);
add(f[i][k+2], f[j][k] * f[s-j][k+1] % MOD);

其中 i 爲當前平衡樹的節點數目,j 爲平衡樹左子樹節點數目,sj=i1j 爲平衡樹右子樹節點數目,k 爲枚舉的高度。
因爲高度之差不超過1,所以右子樹的高度只能爲 k1,k,k+1
這樣直接轉移會T,所以需要優化,可以注意到 f[j][k] 裏很多狀態都是無效的,自然就可以去優化這個地方!

B-代碼

#include <bits/stdc++.h>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>  P;
const int N = 2005,MOD = 7+1e9;
LL f[N][N];
void add(LL& x, LL y)
{
    x += y;
    if(x >= MOD) x -= MOD;
}
int L[N], R[N];
void init()
{
    memset(f, 0, sizeof f);
    f[0][0] = f[1][1] = 1LL;
    L[1] = 1, R[1] = 1;
    for(int i = 2;i <= 2000;i ++)
    {
        int s = i - 1;
        for(int j = 0;j <= s;j ++)
        {
            for(int k = L[j];k <= R[j];k ++)
            {
                if(k > 0) add(f[i][k+1], f[j][k] * f[s-j][k-1] % MOD);
                add(f[i][k+1], f[j][k] * f[s-j][k] % MOD);
                add(f[i][k+2], f[j][k] * f[s-j][k+1] % MOD);
            }
        }
        for(int j = 0;j <= i;j ++)
        {
            if(f[i][j] != 0)
            {
                L[i] = j;
                break;
            }
        }
        for(int j = i;j >= 0;j --)
        {
            if(f[i][j] != 0)
            {
                R[i] = j;
                break;
            }
        }
    }
}
int main()
{
    init();
    int n;
    scanf("%d", &n);
    LL ans = 0;
    for(int i = 0;i <= n;i ++) add(ans, f[n][i]);
    printf("%d\n", (int)ans);
}

E-第K大區間2

定義一個長度爲奇數的區間的值爲其所包含的的元素的中位數。
現給出n個數,求將所有長度爲奇數的區間的值排序後,第K大的值爲多少。

二分答案t,統計中位數大於等於 t 的區間有多少個。
ai 爲前 i 個數中有 ai 個數 >=t ,若奇數區間 [l,r] 的中位數 >=t ,則 (aral1)2>rl , 即 (ar2r)>(al12l)
bi=ai2i ,統計每個bi 有多少個 bj<bi (j<iji 奇偶性不同)
總複雜度 O(nlognlogn)

E-代碼

#include <bits/stdc++.h>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>  P;
const int N = 1e5 + 10,MOD = 7+1e9;
int a[N], n;
int A[N];
int osum[2*N], esum[2*N];
void update(int *A, int p,int val)
{
    while(p < 2*N)
    {
        A[p] += val;
        p += p&(-p);
    }
}
int read(int *A, int p)
{
    int res = 0;
    while(p)
    {
        res += A[p];
        p -= p&(-p);
    }
    return res;
}
int Vs(int x) {return n + 1 + x;}
LL check(int x)
{
    LL cnt = 0;
    int BASE = n + 1;
    memset(osum, 0, sizeof osum);
    memset(esum, 0, sizeof esum);
    update(esum, Vs(0), 1);
    for(int i = 1;i <= n;i ++)
    {
        A[i] = A[i-1] + (a[i] >= x);
        if(i&1) 
        {
            cnt += read(esum, Vs(2 * A[i] - i - 1));
            update(osum, Vs(2 * A[i] - i), 1);
        }
        else 
        {
            cnt += read(osum, Vs(2 * A[i] - i - 1));
            update(esum, Vs(2 * A[i] - i), 1);
        }
    }
    return cnt;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int L = INF, R = -1;
    LL k;
    scanf("%d%lld", &n, &k);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d", &a[i]);
        L = min(L, a[i]), R = max(R, a[i]);
    }
    R ++;
    while(L <= R)
    {
        int mid = (L + R) >> 1;
        if(check(mid) >= k) L = mid + 1;
        else R = mid - 1; 
    }
    printf("%d\n", R);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章