E. Fluctuations of Mana
题目
法师将按固定顺序访问n个魔法资源。我们知道,在访问第i个来源后,ai会改变法力值(这个数字可以是正的,负的或零)。如果法师的法力值变为负值,他就会死亡。在旅程的开始,法师应该拥有多少魔法值才能成功访问所有的n个资源并存活?
输入
第一行包含一个整数n(1≤n≤500000)-魔法资源的数量。
第二行包含n个整数ai(−10^9
≤ai≤10^9)-访问第i个资源后的魔法值变化。
输出
输出一个整数——法师成功完成旅程所需的最小法力值。
代码
package 训练5_15;
import java.util.Arrays;
import java.util.Scanner;
public class E {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int []a=new int[n];
long []b=new long[n];
for(int i=0;i<n;i++) {
a[i]=sc.nextInt();
}
//前缀和求最值
b[0]=a[0];
for(int j=1;j<n;j++) {
b[j]=a[j]+b[j-1];
}
Arrays.sort(b);
System.out.println(b[0]>=0?0:-b[0]);
}
}
分析:
保证过程中法师的法力值一直是大于等于零(>=0),即是求前缀和。前缀和数组进行排序,最小的那个如果大于等于零,则起初的法力值是0,否则是最小值的负数。
F. Moving Target
题目
你在射击场。你面前有n个窗口,从左到右排成一行(最左边的窗口编号为1,最右边的窗口编号为n)。其中一个窗口后面有一个目标。目标的确切位置是未知的,也没有办法确定。当你向其中一个窗口射击时,如果你击中了目标,你就赢了;如果你没有击中目标,如果目标不在最右边的窗口后面,就会向右移动一个窗口。
你必须创造一种能够以最少的射击次数击中目标的策略。
输入
输入包含一个整数n(1≤n≤1000)-窗口数。
输出
在第一行输出整数k(1≤k≤n) -最小的命中目标的次数。
在第二行输出k个整数ai(1≤ai≤n) -要射击的窗口号序列。
注意,当你击中目标后立即获胜时,存在一种决定性策略允许你在最少的射击次数中获胜。
如果有多个可能的答案,则输出其中任何一个。
代码
package 训练5_15;
import java.util.Scanner;
public class F {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int res=0;
if(n%2==0) {
res=n/2+1;
}else {
res=(n+1)/2;
}
System.out.println(res);
for(int i=0;i<(n+1)/2;i++) {
System.out.print((2*i+1)+" ");
}
if(n%2==0) {
System.out.print(n);
}
}
}
分析
构造一个 1 3 5 … 的数列,注意特判奇偶。如果是奇数,则有(n+1)/2个;如果是偶数,则是n/2+1个,还要输出最后一个窗口编号。
H. Tree Painting
题目
给定一棵有n个顶点和(n−1)条边的树。在开始时,它的边缘和顶点不被绘制。您可以在树中选择两个顶点,绘制它们之间的路径(绘制该路径上的所有顶点和边)。
绘制整个树(所有边和所有顶点)的最小操作数是多少?
输入
第一行包含整数n(2≤n≤200000)-树中的顶点数。
接下来的(n−1)行包含两个整数ui,vi(1≤ui,vi≤n,ui≠vi) -由第i条边连接的顶点。
输出
输出一个整数—绘制树的最小操作数。
代码
package 训练5_15;
import java.util.Scanner;
public class H {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int []a=new int[n+1];
int count=0;
for(int i=1;i<n;i++) {
int u=sc.nextInt();
int v=sc.nextInt();
a[u]++;
a[v]++;
}
for(int i=0;i<n+1;i++) {
if(a[i]==1) {
count++;
}
}
System.out.println((count+1)/2);
}
}
分析
最优策略必定是每次选择两个叶子节点,然后将这两个节点间的路径染色,因此结果为 (叶子节点数+1)/2 。叶子节点的特点是与之相关的只有一条边,所以用一个数组用来统计节点连接边的出现次数,出现一次的为叶子结点。
J. The Battle of Mages
题目
两个法师玩游戏。他们都有自己的一套生物。每个生物的特征都是整数——它的力量。在游戏开始时,每个法师从他们的生物集合中召唤出k个不同的随机生物,并且k个生物的每个子集可以被同等几率召唤。法师召唤的所有生物中拥有更大的力量则获胜。如果两种力量的总和相等,这个过程就会重复。如果两个法师的每个生物子集都有相同的力量,则宣布比赛结束。
事实证明,如果k=1或k=3,第一个法师就有更大的胜算,如果k=2,第二个法师就有更大的胜算。你必须给出第一个和第二个法师的生物的例子。
输入
这个问题只有一个测试,它是空的。
输出
在第一行输出一个整数n1(3≤n1≤10)-第一个法师集合中的生物数量。
在第二行输出n1整数S1i(1≤S1i≤10)-第一个法师的生物的力量。
在第三行输出一个整数n2(3≤n2≤10)-在第二个法师的集合中的生物数量。
在第四行输出n2个整数S2i(1≤S2i≤10)-第二个法师的生物的力量。
如果有多个可能的答案,则输出其中任何一个。保证给定约束条件下的解存在。
例子
input
空
output
3
1 2 3
3
2 2 2
请注意
输出示例并不是问题的答案,给出它只是为了更好地理解输出格式和澄清问题语句。
第一个法师有三个生物,他们的力量是1,2和3。第二个法师有三个生物,他们所有的力量都等于2。
如果k=1,第二个法师总是固定力量为2。如果第一个法师召唤该生物的力量为2,此过程将重复。如果他召唤出力量为3的生物,他获胜,而力量为1的生物则失败。第一个法师获胜的概率是0.5,但问题要求第一个法师拥有更好的机会。
如果k=2,第二个法师的力量总是4。第一法师可以召唤生物的子集:(1,2),(1,3),(2,3)。如果是(1,2),第一个法师失败(3 < 4),如果是在比赛开始(1,3)-(4 = 4),如果是(2,3),他赢了。结果的概率还是0.5,但是第二个法师在这种情况下应该有更好的机会。
如果k=3,第一个和第二个法师的子集总是(1,2,3)和(2,2,2)。根据规则,在这种情况下会宣布抽签,所以第一个法师获胜的概率不会大。
代码
package 训练5_15;
public class J {
public static void main(String[] args) {
System.out.println(3);
System.out.print(2+" "+7+" "+7);
System.out.println();
System.out.println(3);
System.out.print(5+" "+5+" "+5);
}
}
分析
要求:如果k=1或k=3,第一个法师就有更大的胜算,如果k=2,第二个法师就有更大的胜算。
K. Table
K题链接
可能有4根长度不同的棒。它们可以作为桌子的腿,这样:
腿在某些矩形的顶点上保持垂直;
桌子的表面,可能是倾斜的,接触到所有的四条腿?
输入
输入包含4个整数a1, a2, a3, a4(1≤ai≤109)-条形的长度。
输出
输出“YES”或“NO”,这取决于是否可以用给定的棒子制作一个桌子。
package 训练5_15;
import java.util.Arrays;
import java.util.Scanner;
public class K {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int []a=new int[4];
for(int i=0;i<4;i++) {
a[i]=sc.nextInt();
}
Arrays.sort(a);
if(a[3] == (a[2] + a[1] - a[0])) {
System.out.println("YES");
}else{
System.out.println("NO");
}
}
}
分析
保证桌面是一个平面,即满足a[3] == (a[2] + a[1] - a[0]。
L. The Dragon Land
题目
一个英雄要去龙的土地上旅行。龙地是一条路,沿着这条路有许多龙的巢穴。英雄会沿着这条路,永不回头。
路过龙穴,有可能与龙搏斗,杀死他并获得ai金。但它并不总是有利可图,杀死所有的龙、武器和盔甲磨损。在第一次战斗英雄将不得不花1黄金修复它们,在第二次战役花2黄金,k的战斗后,他将不得不花k黄金。
一开始英雄没有金子。在他的旅程的任何时刻,在此之后,英雄不可能拥有负数量的金币。
英雄在旅途中可以获得多少金币?
输入
第一行包含整数n(1≤n≤200000)——龙穴的个数。
第二行包含n个整数ai(1≤ai≤109)-英雄对抗第i条龙所能获得的金币数量。
输出
输出一个整数-最大的英雄的利润。
例子
input
5
8 2 4 9 1
output
15
代码
package 训练5_15;
import java.util.Arrays;
import java.util.Scanner;
public class L {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
long []a=new long[n];
long []b=new long[n+1];
long count=0;
for(int i=0;i<n;i++) {
a[i]=sc.nextInt();
}
Arrays.sort(a);
int num=1;
for(int i=n-1;i>=0;i--) {
if((a[i]-num)>0) {
count+=(a[i]-num);
num++;
}
}
System.out.println(count);
}
}
分析
英雄路过龙穴,分为搏斗或者不搏斗,则取决于是否有利可图。即获得的金币大于失去的金币,则搏斗,否则不搏斗。根据题意,可以不按照顺序来与龙进行战斗,所以为了获得金币最大化,则根据获得的金币大小进行排序。
M. Notifications
题目
Vasya正坐在电脑前。有时他会收到关于他最喜欢的Youtube频道新视频的通知。然后,
如果他现在没有在看任何视频,他就会点击通知,开始看视频直到结束;
如果他现在已经在看视频,他会先看完所有未完成的视频(之前他已经收到通知),然后点击新的通知,观看新视频直到结束。
给你n个通知参数:第i个通知在时间点ti收到,包含长度为di的视频。找出Vasya什么时候会停止看最后一个视频。
输入
第一行为整数n(1≤n≤200000)—通知个数。
接下来的n行分别包含两个整数ti和di(1≤ti,di≤109),即Vasya收到第i个通知的时刻,以及该通知中视频的长度。
所有的ti构成非递减序列,即对于所有i从1到(n−1),ti≤ti+1。
输出
输出一个整数----时间的时刻,Vasya将停止观看最后一个视频。
例子
input
5
1 4
3 3
6 1
10 2
10 3
output
15
package 训练5_15;
import java.util.Scanner;
public class M {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
long []a=new long[n];
long []b=new long[n];
long total=a[0];
for(int i=0;i<n;i++) {
a[i]=sc.nextInt();
b[i]=sc.nextInt();
if(a[i]<=total) {
total+=b[i];
}else {
total+=Math.abs(total-a[i])+b[i];
}
}
System.out.println(total);
}
}
分析
如果通知在看完上一个视频之前,直接加上当前视频所花费的时间,如果通知在看完上一个视频之后还要加上看完上一个视频到收到通知的时间间隔。