NOI 2015题解
[luogu P2168] [NOI2015]荷马史诗
就是k叉哈夫曼树
考虑二叉的时候就是每次取最小的两个合并
k叉就是每次取k个合并
这题唯一要注意的就是要补0
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n, k;
ll x;
priority_queue<pair<ll, ll>, vector<pair<ll, ll> >, greater<pair<ll, ll> > > q;
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++) scanf("%lld", &x), q.push(make_pair(x, 0));
for(int i = 1; i <= (k - 1 - (n - 1) % (k - 1)) % (k - 1); i ++) q.push(make_pair(0, 0));
ll ans = 0;
while(q.size() > 1) {
ll s = 0, dep = 0;
for(int i = 1; i <= k; i ++) {
s += q.top().first;
dep = max(dep, q.top().second); q.pop();
}
ans += s, q.push(make_pair(s, dep + 1));
}
printf("%lld\n%lld", ans, q.top().second);
return 0;
}
[luogu P1955] [NOI2015]程序自动分析
首先离散化
然后先考虑相等的,可以用并查集维护联通快
然后不等的就相当于询问x, y是否在同一个联通块里面
code:
#include<bits/stdc++.h>
#define N 2000005
using namespace std;
struct A {
int x, y, z;
} a[N];
int cmp(A x, A y) {
return x.z > y.z;
}
int fa[N], t, n, sz, b[N];
int get(int x) {
return fa[x] == x? x : (fa[x] = get(fa[x]));
}
void merge(int x, int y) {
x = get(x), y = get(y);
fa[x] = y;
}
int main() {
scanf("%d", &t);
while(t --) {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z), b[++ sz] = a[i].x, b[++ sz] = a[i].y;
sort(b + 1, b + 1 + sz);
for(int i = 1; i <= n; i ++) {
a[i].x = lower_bound(b + 1, b + 1 + sz, a[i].x) - b;
a[i].y = lower_bound(b + 1, b + 1 + sz, a[i].y) - b;
}
for(int i = 1; i <= sz; i ++) fa[i] = i;
sort(a + 1, a + 1 + n, cmp);
for(int i = 1; i <= n; i ++) if(a[i].z == 1) merge(a[i].x, a[i].y);
int F = 0;
for(int i = 1; i <= n; i ++) if(a[i].z == 0) {
int x = get(a[i].x), y = get(a[i].y);
if(x == y) F = 1;
}
if(F) printf("NO\n");
else printf("YES\n");
}
return 0;
}
[P2146] [NOI2015]软件包管理器
树剖板子题,没什么好说的
code:
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
struct edge {
int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v) {
e[eid].v = v;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int fa[N], dep[N], size[N], w[N], top[N], id[N], tot, Lef[N], Righ[N], n, q;
void dfs(int u) {
size[u] = 1;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v;
dep[v] = dep[u] + 1, fa[v] = u;
dfs(v);
if(size[v] > size[w[u]]) w[u] = v;
size[u] += size[v];
}
}
void dfss(int u) {
id[u] = ++ tot; Lef[u] = tot;
if(w[u]) top[w[u]] = top[u], dfss(w[u]);
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v;
if(v == w[u]) continue;
top[v] = v;
dfss(v);
}
Righ[u] = tot;
}
int sum[N << 3], tag[N << 3];
void update(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void pushdown(int rt, int l, int r) {
int mid = (l + r) >> 1;
if(tag[rt] == 1) {
sum[rt << 1] = mid - l + 1;
sum[rt << 1 | 1] = r - mid;
tag[rt << 1] = tag[rt << 1 | 1] = tag[rt];
}
if(tag[rt] == 2) {
sum[rt << 1] = sum[rt << 1 | 1] = 0;
tag[rt << 1] = tag[rt << 1 | 1] = tag[rt];
}
tag[rt] = 0;
}
void add(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) {
sum[rt] = r - l + 1;
tag[rt] = 1;
return;
}
pushdown(rt, l, r);
int mid = (l + r) >> 1;
if(L <= mid) add(rt << 1, l, mid, L, R);
if(R > mid) add(rt << 1 | 1, mid + 1, r, L, R);
update(rt);
}
void del(int rt, int l, int r, int L, int R) {
if(L <= l && r <= R) {
sum[rt] = 0;
tag[rt] = 2;
return;
}
pushdown(rt, l, r);
int mid = (l + r) >> 1;
if(L <= mid) del(rt << 1, l, mid, L, R);
if(R > mid) del(rt << 1 | 1, mid + 1, r, L, R);
update(rt);
}
int query(int rt, int l, int r, int L, int R) { //printf("%d %d %d %d %d %d\n", rt, l, r, L, R, sum[rt]);
if(L <= l && r <= R) return sum[rt];
pushdown(rt, l, r);
int mid = (l + r) >> 1, ret = 0;
if(L <= mid) ret += query(rt << 1, l, mid, L, R);
if(R > mid) ret += query(rt << 1 | 1, mid + 1, r, L, R);
return ret;
}
void Add(int x) {
while(top[x] != 1) {
add(1, 1, n, id[top[x]], id[x]);
x = fa[top[x]];
}
add(1, 1, n, id[top[x]], id[x]);
}
void Del(int x) {
while(top[x] != 1) {
del(1, 1, n, id[top[x]], id[x]);
x = fa[top[x]];
}
del(1, 1, n, id[top[x]], id[x]);
}
int Query(int x) {
int ret = 0;
while(top[x] != 1) { //printf("%d ", x);
ret += query(1, 1, n, id[top[x]], id[x]);
x = fa[top[x]];
}
ret += query(1, 1, n, id[top[x]], id[x]);
return ret;
}
int main() { init();
scanf("%d", &n);
for(int i = 2, x; i <= n; i ++) {
scanf("%d", &x);
x ++;
insert(x, i);
}
fa[1] = 1, dep[1] = 1, top[1] = 1;
dfs(1);
dfss(1);
scanf("%d", &q);
while(q --) {
char ch[13]; int x;
scanf(" %s %d", &ch, &x);
x ++;
if(ch[0] == 'i') {
printf("%d\n", dep[x] - Query(x));
Add(x);
} else {
printf("%d\n", query(1, 1, n, Lef[x], Righ[x]));
del(1, 1, n, Lef[x], Righ[x]);
}
}
return 0;
}
[P2178] [NOI2015]品酒大会
to be continue……
P2150 [NOI2015]寿司晚宴
考虑
n
<
=
30
n<=30
n<=30质数只有10个
然后直接状压
d
p
[
S
1
]
[
S
2
]
dp[S1][S2]
dp[S1][S2]表示甲选的集合为S1,乙选的集合为S2
DP方程显然
然后考虑
n
<
=
500
n<=500
n<=500
发现除了最大的质数,其他的都是
<
=
s
q
r
t
(
n
)
<=sqrt(n)
<=sqrt(n)的
只有
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
2,3,5,7,11,13,17,19
2,3,5,7,11,13,17,19这8个
然后按照最大的质数因子排序,相同的不在一起转移就行了
注意一下不选的情况是算重复的,要减掉
code:
#include<bits/stdc++.h>
#define int long long
#define N 505
using namespace std;
int prime[12] = {2, 3, 5, 7, 11, 13, 17, 19};
int n, mod, dp[N][N], f1[N][N], f2[N][N];
struct A {
int sta, big;
} a[N];
int cmp(A x, A y) {
return x.big < y.big;
}
void MOD(int & x) {
x = (x + mod) % mod;
}
signed main() {
scanf("%lld%lld", &n, &mod);
for(int i = 2; i <= n; i ++) {
int x = i;
for(int j = 0; j < 8; j ++) {
while(x % prime[j] == 0) x /= prime[j], a[i].sta |= (1 << j);
}
a[i].big = x;
}
sort(a + 1, a + 1 + n, cmp);
dp[0][0] = 1;
for(int k = 2; k <= n; k ++) {
if(a[k].big == 1 || a[k].big != a[k - 1].big) {
for(int i = 0; i <= 255; i ++)
for(int j = 0; j <= 255; j ++)
f1[i][j] = f2[i][j] = dp[i][j];
}
for(int i = 255; i >= 0; i --)
for(int j = 255; j >= 0; j --) {
if(i & j) continue;
if((j & a[k].sta) == 0) f1[i | a[k].sta][j] += f1[i][j], MOD(f1[i][j]);
if((i & a[k].sta) == 0) f2[i][j | a[k].sta] += f2[i][j], MOD(f2[i][j]);
}
if(a[k].big == 1 || a[k].big != a[k + 1].big) {
for(int i = 0; i <= 255; i ++)
for(int j = 0; j <= 255; j ++)
dp[i][j] = f1[i][j] + f2[i][j] - dp[i][j], MOD(dp[i][j]);//减去算重复的
}
}
int ans = 0;
for(int i = 0; i <= 255; i ++)
for(int j = 0; j <= 255; j ++)
ans += dp[i][j], MOD(ans);
printf("%lld", ans);
return 0;
}