题目
题目描述
小明在他的果园里种了一些苹果树,这些苹果树排列成一个圆。为了保证苹果的品质,在种植过程中要进行疏果操作。为了更及时地完成疏果操作,小明会不时地检查每棵树的状态,根据需要进行疏果。检查时,如果发现可能有苹果从树上掉落,小明会重新统计树上的苹果个数(然后根据之前的记录就可以判断是否有苹果掉落了)。在全部操作结束后,请帮助小明统计相关的信息。
输入格式
从标准输入读入数据。
第1行包含一个正整数N,表示苹果树的棵数。
第1+i行(1<= i <= N),每行的格式为mi,ai1,ai2,…,aimi。其中,第一个正整数mi表示本行后面的整数个数。后续的mi个整数表示小明对第i棵苹果树的操作记录。若aij(1<= j <= mi)为正整数,则表示小明进行了重新统计该棵树上的苹果个数的操作,统计的苹果个数为aij;若为零或负数,则表示一次疏果操作,去掉的苹果个数为|aij|。
输入保证一定是正确的,满足:
1. aij > 0,即对于每棵树的记录,第一个操作一定是统计苹果个数(初始状态,此时不用判断是否有苹果掉落);
2. 每次疏果操作保证操作后树上的苹果个数仍为正。
输出格式
输出到标准输出。
输出只有一行,包含三个整数T、D、E。其中,
T 为全部蔬果操作结束后所有苹果树上剩下的苹果总数(假设每棵苹果树在最后一次统计苹果个数操作后苹果不会因为疏果以外的原因减少);
D 为发生苹果掉落的苹果树的棵数;
E 为相邻连续三棵树发生苹果掉落情况的组数。
对于第三个统计量的解释:N棵苹果树A1,A2,…,AN排列成一个圆,那么A1与A2相邻,A2与A3相邻,…,AN-1与AN相邻,AN与A1相邻。如果Ai-1,Ai,Ai+1这三棵树都发生了苹果掉落的情况,则记为一组。形式化的,有
其中,Drop(Ai)表示苹果树Ai是否发生苹果掉落的情况,Pred(Ai)表示Ai的前一棵树Ai-1(如果i>1)或者AN(如果i=1),Succ(Ai)表示Ai的后一棵树Ai+1(如果i<N)或者A1(如果i=N)。
样例
样例1
输入:
4
4 74 -7 -12 -5
5 73 -8 -6 59 -4
5 76 -5 -10 60 -2
5 80 -6 -15 59 0
输出:
222 1 0
解释:
全部操作结束后,第1棵树上剩下的苹果个数为74-7-12-5 = 50,第2棵为59-4=55,第3棵为60-2=58,第4棵为59-0=59。因此T=50+55+58+59=222。
其中,第3棵树在第2次统计之前剩下的苹果个数为76-5-10=61>60,因此发生了苹果掉落的情况。可以检验其他的树没有这种情况,因此D=1。
没有连续三棵树都发生苹果掉落的情况,因此E=0。
样例2
输入:
5
4 10 0 9 0
4 10 -2 7 0
2 10 0
4 10 -3 5 0
4 10 -1 8 0
输出:
39 4 2
解释:
第1、2、4、5棵树发生了苹果掉落的情况,因此D=4.其中,连续三棵树都发生苹果掉落情况的有(5,1,2)和(4,5,1),因此E=2。
子任务
提示
如果你的程序没有实现统计D和E的功能,请按照D=0,E=0输出结果,这样如果T的统计正确能够得到一部分分数。
如果你的程序没有实现统计E的功能,请按照E=0输出结果,这样如果T和D的统计正确能够得到一部分分数。
分析
n太大,mi太大,尽量不要尝试将所有数据存储下来在进行分析,但是计算连续三棵树发生苹果掉落情况的的组数时不能只分析一条数据,所以我们可以为每棵树添加一个标记,记录这棵树是否发生了苹果掉落。
具体算法已在程序中用注释给出。(我写的注释挺详细的)
代码
/*
2019/12/28
csp试题2:小明种苹果(绪)
*/
#include <iostream>
using namespace std;
long long T = 0; //剩下的苹果总数
int D = 0; //发生苹果掉落的苹果树的棵数
int E = 0; //连续三棵树发生苹果掉落情况的的组数
int drop_trees[1001]; //标记每棵树是否发生了苹果掉落
int main(){
//1.1接收数据
int n;
cin >>n; //苹果树的棵数
//1.2初始化drop_trees[],0表示没有发生掉落,1表示发生了掉落
for(int i=0; i<1001; i++){
drop_trees[i] = 0; //都初始化为没有发生苹果掉落
}
//2 接收每条数据并处理
//对于第i棵树,需要计算其剩余苹果数,将其加到T上
//然后判断其是否发生了苹果掉落,将判断结果保存在drop_trees[]中
//2.1计算其剩余苹果数
int num = -1; //即mi,每条数据中表示操作的数的个数
for(int i=0; i<n; i++){
cin >>num; //接收每条数据中的第一个数
int arr[num];
for(int j=0; j<num; j++){
cin >> arr[j];
}
int temp = arr[0]; //表示当前树上有多少苹果
for(int j=1; j<num; j++){
if(arr[j] < 0){ //进行疏果操作
temp = temp + arr[j]; //更新当前树上苹果树
}
if(arr[j] > 0 && temp > arr[j]){ //进行统计苹果个数操作且发生了苹果掉落
drop_trees[i] = 1; //标记第i棵树发生了苹果掉落
temp = arr[j]; //更新当前树上苹果数
}
}
T = T + temp; //苹果总数 = 其他树上的苹果树 + 第i棵树上剩余苹果数
}
//2.2处理drop_trees[], 计算D和E
for(int i=0; i<n; i++){
if(drop_trees[i] == 1){
D++;
}
if(drop_trees[i%n]==1 && drop_trees[(i+1)%n]==1 && drop_trees[(i+2)%n]==1){
E++;
}
}
//3 输出结果
cout <<T <<" " <<D <<" " <<E<<endl;
return 0;
}
总结
计算连续三棵树发生苹果掉落情况的的组数这个问题其实挺难的,既要在整体的数据中提取数据,又要在具体的数据上考虑循环,我用了取余的方法处理循环问题,看起来挺简单的。
还有最后一篇试题2,就要干试题3了,慌得一批。。。