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;
}