这场比赛出的还行吧,挺可做的。
T1:
长度为n+1的序列,其中的每个数都是不大于n的正整数,且n以内每个数至少出现一次,求对于每一个K,本质不同子序列有多少个。
你先不考虑重复,每个K就是:C(n+1,K)。
你找出相同的位置:l1,l2。
那么会出现重复的就是:C(n + l1 - l2,K-1)然后即可。。。
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch =getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
int a[110000];
LL jc[110000], inv[110000];
LL pow_mod(LL a, int k) {
LL ans = 1;
while(k) {
if(k & 1) (ans = ans * a) %= mod;
(a *= a) %= mod, k /= 2;
} return ans;
}
LL C(int n, int m) {
if(m > n) return 0;
return jc[n] * inv[m] % mod * inv[n - m] % mod;
}
int main() {
int n = read();
int l1, l2;
jc[0] = inv[0] = 1;
for(int i = 1; i <= n + 1; i++) jc[i] = jc[i - 1] * i % mod;
inv[n + 1] = pow_mod(jc[n + 1], mod - 2);
for(int i = n; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
for(int i = 1; i <= n + 1; i++) {
int x = read();
if(a[x]) l1 = a[x], l2 = i;
a[x] = i;
}
for(int i = 1; i <= n + 1; i++) {
LL u1 = C(n + 1, i);
LL u2 = C(l1 + n - l2, i - 1);
printf("%lld\n", (u1 - u2 + mod) % mod);
}
return 0;
}
T2:
一个长度为n的序列A,从中删去恰好K个元素,每删一个元素就往左,记cnt为Ai=i的个数,求cnt的最大值。
其实这道题跟[POI2007]堆积木Klo很像,只是多了一个限制条件。
满足转移的话需要三个条件:
j
<
i
j < i
j<i,
a
[
j
]
<
a
[
i
]
a[j] < a[i]
a[j]<a[i],
j
−
a
[
j
]
<
=
i
−
a
[
i
]
j - a[j] <= i - a[i]
j−a[j]<=i−a[i]
其实后两个可以推出第一个。
于是你就排一遍序,求最长上升子序列即可。
然后考虑限制条件,你发现对于每删一个数的本质其实是,他右边的ai-i全部减一,
那么删K次其实相当于你只要控制ai-i的范围在K以内,若不足K你就判断后面是否够你删。。。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch =getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct node {
int x, y, h, id;
} a[1100000];
int n, k, f[1100000], s[1100000];
int q[1100000];
bool cmp1(node a, node b) {return a.y < b.y;}
bool cmp2(node a, node b) {
if(a.x == b.x) return a.y > b.y;
return a.x < b.x;
}
int lowbit(int x) {return x & -x;}
void change(int x, int c) {for(int i = x; i <= n; i += lowbit(i)) s[i] = _max(s[i], c);}
int getmax(int x) {int maxx = -999999999; for(int i = x; i; i -= lowbit(i)) maxx = _max(maxx, s[i]); return maxx;}
int main() {
n = read(), k = read(); n++; a[1].y = 1;
for(int i = 2; i <= n; i++) a[i].x = read(), a[i].y = a[i].h = i - a[i].x, a[i].id = i - 1, a[i].h--;
sort(a + 1, a + n + 1, cmp1);
int id = 0; q[0] = 999999999;
for(int i = 1; i <= n; i++) {
if(a[i].y != q[id]) q[++id] = a[i].y;
a[i].y = id;
} sort(a + 1, a + n + 1, cmp2);
memset(s, 128, sizeof(s));
int ans = 0; change(a[1].y, 0);
for(int i = 2; i <= n; i++) {
f[i] = getmax(a[i].y) + 1;
change(a[i].y, f[i]);
}
for(int i = 1; i <= n; i++) {
if(a[i].h >= 0 && a[i].h <= k) {
if(n - a[i].id >= k - a[i].h) ans = _max(ans, f[i]);
}
} printf("%d\n", ans);
return 0;
}
T3:
小D梦见了一棵包含n个节点的树,这棵树包含着神秘的能量。具体来讲,对于这棵树中的一个联通块,它的能量为它拥有的节点中编号连续的最长的一段。举例来说,如果一个连通块包含了原树中编号为{1,3,4,5,7,8}的节点,那么编号连续的最长的一段为{3,4,5}。它所具有的能量值为3。
小D想要从这棵树中获得能量,但由于种种原因,小D只能从这棵树中选取一个节点数不大于k的连通块并获得它的能量值,小D想要知道他能取得的最大能量值是多少。
一棵树包含n个节点的树就是有n个点,n−1条边的连通图。
这题你考虑维护一个双指针,使其满足选l~r的连通块小于等于k
然后对于如何求一个连通块的的大小,你可以按照dfs序排一个序,相邻求距,头尾求距,再除二加一即为联通块大小,这个用双指针维护的话,你可以用set维护。。。
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define It set<int>::iterator
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch =getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct edge {
int x, y, next;
} e[210000]; int len, last[110000];
int id, sum, K, dfn[110000], bak[110000], dep[110000], fa[20][110000];
set<int>q;
void ins(int x, int y) {
e[++len].x = x; e[len].y = y;
e[len].next = last[x]; last[x] = len;
}
void dfs(int x) {
dfn[x] = ++id, bak[id] = x;
for(int i = 1; (1 << i) <= dep[x]; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]];
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa[0][x]) {
fa[0][y] = x;
dep[y] = dep[x] + 1;
dfs(y);
}
}
}
int LCA(int x, int y) {
if(dep[x] > dep[y]) swap(x, y);
int X = x, Y = y;
for(int i = 18; i >= 0; i--) if(dep[y] - dep[x] >= (1 << i)){
y = fa[i][y];
} if(x == y) return dep[Y] - dep[X];
for(int i = 18; i >= 0; i--) if(fa[i][x] != fa[i][y]){
x = fa[i][x], y = fa[i][y];
} return dep[Y] + dep[X] - dep[fa[0][x]] * 2;
}
void ers(int u) {
It hh = q.lower_bound(dfn[u]), h1 = hh;
if(h1 == q.begin()) h1 = q.end(), --h1;
else --h1;
It h2 = hh; ++h2;
if(h2 == q.end()) h2 = q.begin();
int x = *h1, y = *h2;
sum -= LCA(bak[x], u) + LCA(u, bak[y]) - LCA(bak[x], bak[y]);
q.erase(dfn[u]);
}
int main() {
int n = read(); K = read();
for(int i = 1; i < n; i++) {
int x = read(), y = read();
ins(x, y), ins(y, x);
} dfs(1);
int st = 1, ans = 1; q.insert(dfn[1]);
for(int i = 2; i <= n; i++) {
It h2 = q.lower_bound(dfn[i]);
if(h2 == q.end()) h2 = q.begin();
It h1 = h2;
if(h1 == q.begin()) h1 = q.end(), --h1;
else --h1;
int x = *h1, y = *h2;
sum += LCA(bak[x], i) + LCA(i, bak[y]) - LCA(bak[x], bak[y]);
q.insert(dfn[i]);
while(sum / 2 + 1 > K) ers(st++);
ans = _max(ans, i - st + 1);
} printf("%d\n", ans);
return 0;
}