A. Buying Torches
题意:
初始有 1 1 1 根木棒,有两种操作:
- 用 1 1 1 根木棒换 x x x 根木棒
- 用 Y Y Y 根木棒换一个煤炭
需要造 k k k 个火把
每个火把需 1 1 1 根木棒, 1 1 1 个煤炭
问以上两种操作最少需要进行多少次 。
一共需要 k ∗ y + k k*y+k k∗y+k 个木棒减去原本的一根,且每次只能生成 x − 1 x-1 x−1 根。所以计算一共需要生成多少次即可。
AC代码:
const int N = 2e5 + 50;
int n, m, p, q;
int a[N];
int cnt[N];
ll x, y, k;
bool flag;
int l, r, d;
int main()
{
int t;
sd(t);
while (t--)
{
slddd(x, y, k);
ll num = k * y + k - 1;
x--;
ll ans = num / x;
if (num % x)
ans++;
pld(ans+k);
}
return 0;
}
B. Negative Prefixes
题意:
有两个数组 a , b a ,b a,b ,其中 b b b 数组的值为 1 1 1 时,所对应的 a a a 数组的值不可以随便移动
现在可以将 a a a 数组可以移动的值相互交换使得 k k k 最小
定义 k k k:在 a a a 数组中前 j 个数之和小于 0 0 0 , j ϵ [ 1 , n ] j \epsilon [1,n] jϵ[1,n], k k k 为最大的 j j j 的值
输出使得 k k k 最小的排列后的数组
将可以相互交换的 a a a 数组的值从大到小排序,插入即可。
AC代码:
const int N = 2e5 + 50;
int n, m, p, q;
int a[N], l[N];
bool flag;
int main()
{
int t;
sd(t);
while (t--)
{
int v[N];
int cnt = 0;
sd(n);
rep(i, 1, n)
sd(a[i]);
rep(i, 1, n)
{
sd(l[i]);
if (!l[i])
v[++cnt] = a[i];
}
sort(v + 1, v + cnt + 1);
rep(i, 1, n)
{
if (!l[i])
{
a[i] = v[cnt--];
}
}
rep(i, 1, n)
printf("%d%c", a[i], i == n ? '\n' : ' ');
}
return 0;
}
C. Mortal Kombat Tower
题意:
有两个人玩游戏, a a a 先走, b b b 再走,每人最多走一步,最少走两步,给出数组 b o s s boss boss ,当 b o s s boss boss 的值为 1 1 1 时, a a a 需花费 1 1 1 金币才可以走, b o s s boss boss 为 0 0 0 时不用, b b b 随便走。问最少花费多少金币 。
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示杀前i个怪, j j j号玩家杀的第 i i i 个怪的时候,你朋友杀的 1 1 1 型怪个数的最小值。
AC代码:
const int N = 2e5 + 50;
int n, m, p, q;
int a[N], l[N];
bool flag;
int dp[N][2];
int main()
{
int t;
sd(t);
while (t--)
{
sd(n);
rep(i, 1, n)
sd(a[i]);
dp[0][0] = dp[-1][0] = inf;
rep(i, 1, n)
{
dp[i][0] = min(dp[i - 1][1] + a[i], dp[i - 2][1] + a[i] + a[i - 1]);
dp[i][1] = min(dp[i - 1][0], dp[i - 2][0]);
}
pd(min(dp[n][0], dp[n][1]));
}
return 0;
}
D. Trash Problem
题意:
有
n
n
n 堆垃圾,每一堆的坐标为
x
x
x,合并两堆垃圾的花费为这两堆垃圾的坐标之差的绝对值。
你可以进行
q
q
q 次操作。
1
1
1
x
x
x表示在
x
x
x 位置上增加一堆垃圾,
0
0
0
x
x
x 表示删除
x
x
x 位置上的垃圾。
输出将这
n
n
n 堆垃圾合并成两堆垃圾所需的花费,以及每次操作之后改变的答案。
AC代码:
const int N = 2e5 + 50;
int n, Q;
struct Node
{
int mi, ma; //每一段的最小值、最大值
int max; //这一段中相邻两个数的差的最大值
} tr[N * 4];
int a[N], b[N];
bool vis[N]; //标记每个点是否在当前序列中
int op[N], q[N]; //记录q次操作的询问(离线算法)
void pushup(int u)
{
tr[u].ma = max(tr[u << 1].ma, tr[u << 1 | 1].ma);
if (tr[u << 1].mi == 0 || tr[u << 1 | 1].mi == 0)
tr[u].mi = max(tr[u << 1].mi, tr[u << 1 | 1].mi);
else
tr[u].mi = min(tr[u << 1].mi, tr[u << 1 | 1].mi);
if (tr[u << 1].ma == 0 || tr[u << 1 | 1].mi == 0)
tr[u].max = max(tr[u << 1].max, tr[u << 1 | 1].max);
else
tr[u].max = max(max(tr[u << 1].max, tr[u << 1 | 1].max), tr[u << 1 | 1].mi - tr[u << 1].ma);
}
void build(int u, int l, int r)
{
if (l == r)
{
if (vis[l])
tr[u] = {a[l], a[l], 0};
else
tr[u] = {0, 0, 0};
}
else
{
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int l, int r, int x, bool op)
{
if (l == r)
{
if (op)
tr[u] = {a[l], a[l], 0};
else
tr[u] = {0, 0, 0};
}
else
{
int mid = l + r >> 1;
if (x <= mid)
modify(u << 1, l, mid, x, op);
else
modify(u << 1 | 1, mid + 1, r, x, op);
pushup(u);
}
}
int query()
{
return tr[1].ma - tr[1].mi - tr[1].max;
}
int main()
{
int t;
sdd(n, Q);
mem(vis, false);
rep(i, 1, n)
{
sd(a[i]);
b[i] = a[i];
}
rep(i, 1, Q)
{
sdd(op[i], q[i]);
a[i + n] = q[i];
}
sort(b + 1, b + 1 + n);
sort(a + 1, a + 1 + n + Q);
int cnt = unique(a + 1, a + 1 + n + Q) - a - 1;
rep(i, 1, Q)
q[i] = lower_bound(a + 1, a + 1 + cnt, q[i]) - a;
int k = 1;
rep(i, 1, n)
{
while (b[i] != a[k])
{
k++;
}
vis[k] = true;
}
build(1, 1, cnt);
pd(query());
rep(i, 1, Q)
{
modify(1, 1, cnt, q[i], op[i]);
pd(query());
}
return 0;
}