Noip 模拟练习9
Posted bigyellowdog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noip 模拟练习9相关的知识,希望对你有一定的参考价值。
Noip 模拟练习9
- 较容易。一次AK。
锻炼计划
Description
- 身体是革命的本钱, OIers 不要因为紧张的学习和整天在电脑前而忽视了健
康问题。小 x 设计了自己的锻炼计划,但他不知道这个计划是否可行,换句话
说如果计划不当可能会让他的体力超支,所以小 x 请你帮助他。
一天有 1440 分钟,所以小 x 列出的是这一整天第 1 至第 1440 分钟的计划。
小 x 的体力用一个整数来表示,他会按照计划表进行锻炼,同时,每分钟小 x
的体力会自动增加 1。如果某一分钟末小 x 的体力小于等于零,那么可怜的小 x
就累死了……
Input
- 第一行是用空格分开的两个整数 n,m,分别表示小 x 的初始体力值和计划的
项目数量。
从第二行开始的 m 行,每行描述一个锻炼项目:名称、开始时间 a、结束时
间 b、每分钟耗费的体力(用空格分隔),表示此项目从第 a 分钟初开始,第 b 分
钟末结束。锻炼项目按照开始时间递增顺序给出,不会出现两个项目时间冲突
的情况。
Output
- 输出包括两行,如果计划可行,第一行输出"Accepted",第二行输出这一天
过后最后剩余的体力;否则在第一行输出"Runtime Error",第二行输出在第几分
钟累死。
Sample Input
Basketball 1 10 1
Sample output
Accepted
1140
题解:
- 模拟... ...
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
int n, m;
int a[2005];
int main()
cin >> n >> m;
for(int i = 1; i <= m; i++)
string t; cin >> t;
int u, v, w;
cin >> u >> v >> w;
for(int j = u; j <= v; j++) a[j] += w;
for(int i = 1; i <= 1440; i++)
n++, n -= a[i];
if(n <= 0) cout << "Runtime Error\n" << i; return 0;
cout << "Accepted\n" << n;
return 0;
魔兽争霸
Description
- 小 x 正在销魂地玩魔兽
他正控制着死亡骑士和 n 个食尸鬼(编号 1~n)去打猎
死亡骑士有个魔法,叫做“死亡缠绕”,可以给食尸鬼补充 HP
战斗过程中敌人会对食尸鬼实施攻击,食尸鬼的 HP 会减少
小 x 希望随时知道自己部队的情况,即 HP 值第 k 多的食尸鬼有多少 HP,
以便决定如何施放魔法
请同学们帮助他:)
小 x 向你发出 3 种信号:(下划线在输入数据中表现为空格)
A_i_a 表示敌军向第 i 个食尸鬼发出了攻击,并使第 i 个食尸鬼损失了 a 点
HP ,如果它的 HP<=0, 那么这个食尸鬼就死了 (Undead 也是要死的)。
敌军不会攻击一个已死的食尸鬼。
C_i_a 表示死亡骑士向第 i 个食尸鬼放出了死亡缠绕,并使其增加了 a 点 HP。
HP 值没有上限。
死亡骑士不会向一个已死的食尸鬼发出死亡缠绕
Q_k 表示小 x 向你发出询问
Input
- 第一行,一个正整数 n
以后 n 个整数 表示 n 个食尸鬼的初始 HP
值接着一个正整数 m
以下 m 行 每行一个小 x 发出的信号
Output
- 对于小 x 的每个询问,输出 HP 第 k 多的食尸鬼有多少 HP,如果食尸鬼总
数不足 k 个,输出-1。每个一行数。
最后一行输出一个数:战斗结束后剩余的食尸鬼数
Sample Input
5
1 2 3
4 5
10
Q 2
A 4 6
C 1 4
Q 2
A 2 1
A 3 3
A 1 3
Q 4
C 2 10
Q 1
Sample output
4
5
-1
11
3
题解:
- 平衡树裸题。我用fhq-treap实现。
- 做法就是每次修改一个点就删除修改前的点,再加入修改后的点。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define N 30005
using namespace std;
struct T int l, r, val, dat, size; t[N * 4];
int n, m, root, x, y, z, tot, now;
int a[N];
int read()
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0'; c = getchar();
return x;
int New(int val)
t[++tot].val = val;
t[tot].dat = rand();
t[tot].size = 1;
return tot;
void up(int p) t[p].size = t[t[p].l].size + t[t[p].r].size + 1;
void split(int p, int val, int &x, int &y)
if(!p) x = y = 0; return;
if(t[p].val <= val) x = p, split(t[p].r, val, t[p].r, y);
else y = p, split(t[p].l, val, x, t[p].l);
up(p);
int merge(int x, int y)
if(!x || !y) return x + y;
if(t[x].dat > t[y].dat)
t[x].r = merge(t[x].r, y);
up(x); return x;
else
t[y].l = merge(x, t[y].l);
up(y); return y;
void insert(int val)
split(root, val - 1, x, y);
root = merge(merge(x, New(val)), y);
void erase(int val)
split(root, val, x, z);
split(x, val - 1, x, y);
y = merge(t[y].l, t[y].r);
root = merge(merge(x, y), z);
int valOfRank(int rank)
int p = root;
while(p)
if(t[t[p].l].size + 1 == rank) break;
else if(t[t[p].l].size >= rank) p = t[p].l;
else rank -= t[t[p].l].size + 1, p = t[p].r;
return t[p].val;
int main()
cin >> n, now = n;
for(int i = 1; i <= n; i++)
a[i] = read();
insert(a[i]);
cin >> m;
for(int i = 1; i <= m; i++)
char c[3]; scanf("%s", c);
if(c[0] == 'A')
int pos = read(), val = read();
erase(a[pos]);
a[pos] -= val;
if(a[pos] <= 0) now--;
else insert(a[pos]);
else if(c[0] == 'C')
int pos = read(), val = read();
erase(a[pos]);
a[pos] += val;
insert(a[pos]);
else if(c[0] == 'Q')
int rank = read();
if(now < rank) printf("-1\n");
else printf("%d\n", valOfRank(now - rank + 1));
cout << now;
return 0;
暗黑破坏神
Description
- 无聊中的小 x 玩起了 Diablo I...
游戏的主人公有 n 个魔法
每个魔法分为若干个等级,第 i 个魔法有 p[i]个等级(不包括 0)
每个魔法的每个等级都有一个效果值,一个 j 级的 i 种魔法的效果值为
w[i][j] 魔法升一级需要一本相应的魔法书
购买魔法书需要金币,第 i 个魔法的魔法书价格为 c[i]
而小 x 只有 m 个金币(好孩子不用修改器)
你的任务就是帮助小 x 决定如何购买魔法书才能使所有魔法的效果值之和最
大
开始时所有魔法为 0 级 效果值为 0
Input
- 第一行 用空格隔开的两个整数 n m
以下 n 行 描述 n 个魔法
第 i+1 行描述 第 i 个魔法 格式如下
c[i] p[i] w[i][1] w[i][2] ... w[i][p[i]]
Output
- 第一行输出一个整数,即最大效果值。
以后 n 行输出你的方案:
第 i+1 行有一个整数 v[i] 表示你决定把第 i 个魔法学到 v[i]级
如果有多解 输出花费金币最少的一组
如果还多解 输出任意一组
Sample Input
3 10
1 3 1 2 2
2 3 2 4 6
3 3 2 1 10
Sample output
11
1
0
3
题解:
- 线性dp。
- 设dp(i, j)为处理了前i个魔法,用j个金币获得的最大效果值。
- 通过上一个(i - 1)物品的状态,然后依次取当前物品的不同形态取最优值。
- 比较容易,主要是输出方案。
- 想了一下我用a(i, j)同步记录当算到dp(i, j)时,得到dp(i, j)时,用的是哪个物品。
- ok,搞定。
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 2005
using namespace std;
struct Ans int id, lev; ans[N];
struct A int val, id, lev; a[N][N];
int n, T;
int cnt[N];
int w[N][N], v[N][N], dp[N][N];
bool cmp(Ans x, Ans y) return x.id < y.id;
int main()
cin >> n >> T;
for(int i = 1; i <= n; i++)
int c; cin >> c;
int p; cin >> p;
cnt[i] = p;
for(int j = 1; j <= p; j++)
cin >> v[i][j], w[i][j] = c * j;
for(int i = 1; i <= n; i++)
for(int j = 0; j <= T; j++)
for(int k = 0; k <= cnt[i]; k++)
if(j - w[i][k] >= 0)
if(dp[i - 1][j - w[i][k]] + v[i][k] > dp[i][j])
dp[i][j] = dp[i - 1][j - w[i][k]] + v[i][k];
a[i][j].id = i, a[i][j].lev = k;
a[i][j].val = w[i][k];
else if(dp[i - 1][j - w[i][k]] + v[i][k] == dp[i][j] && w[i][k] < a[i][j].val)
dp[i][j] = dp[i - 1][j - w[i][k]] + v[i][k];
a[i][j].id = i, a[i][j].lev = k;
a[i][j].val = w[i][k];
cout << dp[n][T] << endl;
int now = T;
for(int i = n; i >= 1; i--)
ans[i].id = a[i][now].id;
ans[i].lev = a[i][now].lev;
now = now - a[i][now].val;
sort(ans + 1, ans + 1 + n, cmp);
for(int i = 1; i <= n; i++) cout << ans[i].lev << endl;
return 0;
以上是关于Noip 模拟练习9的主要内容,如果未能解决你的问题,请参考以下文章