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 爲平衡樹左子樹節點數目,s−j=i−1−j 爲平衡樹右子樹節點數目,k 爲枚舉的高度。
因爲高度之差不超過1,所以右子樹的高度只能爲k−1,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 ,則(ar−al−1)∗2>r−l , 即(ar∗2−r)>(al−1∗2−l) 。
設bi=ai∗2−i ,統計每個bi 有多少個bj<bi (j<i 且j 和i 奇偶性不同)
總複雜度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;
}