2011福建省信息学奥林匹克CCF NOIP夏令营第八天训练

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2011福建省信息学奥林匹克CCF NOIP夏令营第八天训练问题名称文件名输入文件输出文件时限分值最大子段和 maxsum1 maxsum1.in maxsum1.out 1s 100 环状最大两段maxsum2 maxsum2.in
maxsum2.out 1s 100 子段和
最大子树和 maxsum3 maxsum3.in maxsum3.out 1s 100 内存限制均为256M 最大子段和(maxsum1)
【问题描述】
给出一段序列,选出其中连续且非空的一段使得这段和最大。

【输入文件】
输入文件maxsum1.in的第一行是一个正整数N,表示了序列的长度。

第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列。

【输出文件】
输入文件maxsum1.out仅包括1个正整数,为最大的子段和是多少。

【样例输入】
7
2 -4
3 -1 2 -
4 3
【样例输出】
4
【样例说明】
2 -4
3 -1 2 -
4 3
【数据规模与约定】
对于40%的数据,有N ? 2000。

对于100%的数据,有N ? 200000。

题目大意:在一个序列中找出一个段连续非空和最大。

设f[i]为取第i个时的最大值,那么f[i]:=max(map[i],map[i]+f[i-1]); Max(f[i])即为所求。

var
a,ans:array[1..200000] of int64;
n,i:longint;
max:int64;
begin
assign(input,'maxsum1.in');
assign(output,'maxsum1.out');
reset(input); rewrite(output);
readln(n);
read(a[1]);
ans[1]:=a[1];
for i:=2 to n do begin
read(a[i]);
if ans[i-1]<0 then ans[i]:=a[i]
else ans[i]:=ans[i-1]+a[i];
end;
max:=-maxlongint;
for i:=1 to n do
if ans[i]>max then max:=ans[i];
writeln(max);
close(input); close(output); end.
环状最大两段子段和(maxsum2)
【问题描述】
给出一段环状序列,即认为A[1]和A[N]是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大。

【输入文件】
输入文件maxsum2.in的第一行是一个正整数N,表示了序列的长度。

第2行包含N个绝对值不大于10000的整数A[i],描述了这段序列,第一个数和第N个数是相邻的。

【输出文件】
输入文件maxsum2.out仅包括1个整数,为最大的两段子段和是多少。

【样例输入】
7
2 -4
3 -1 2 -
4 3
【样例输出】
9
【样例说明】
一段为3 –1 2,一段为3 2
2 -4
3 -1 2 -
4 3
【数据规模与约定】
对于40%的数据,有2 ? N ? 2000。

对于100%的数据,有N ? 200000。

题目大意:在一个环状序列中取两段非空且和最大。

这题很有难度,如何破环为链,用到第一题的方法,
可以发现,结果无非只有两种情况。

—————|———|——————|—————|—————
1、取到的两段在中间,则枚举切割点,分成两段,分别用第一题方法求解,取和最大。

—————|———|——————|—————|—————
2、取到的两段一段在中间,一段在首尾。

发现图2与图1很相似,如果枚举3段红色部分可能会超时。

于是可以枚举两段黑色部分,即找两段连续非空和最小,然后用总和减去这两段黑色部分,再取最大值。

(注意如果总和-黑色=0说明全都不取,而如果都是负数就会出错);也可以全部取负,然后取最大。

var
zheng,fu,zhengmax,fanmax,fumax,fufanmax:array[0..200001] of
longint;
fan,fufan:array[0..200001] of longint;
map,fumap:array[0..200000] of longint;
i,n,sum,maxans,temp:longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
begin
assign(input,'maxsum2.in');
assign(output,'maxsum2.out');
reset(input); rewrite(output);
readln(n);
sum:=0;
for i:=1 to n do begin
read(map[i]);
fumap[i]:=-map[i];
inc(sum,map[i]);
end;
zheng[1]:=map[1]; zhengmax[1]:=map[1];
fu[1]:=fumap[1]; fumax[1]:=fumap[1];
for i:=2 to n do begin
if zheng[i-1]>=0 then zheng[i]:=zheng[i-1]+map[i] else zheng[i]:=map[i];
zhengmax[i]:=max(zhengmax[i-1],zheng[i]);
if fu[i-1]>=0 then fu[i]:=fu[i-1]+fumap[i]
else fu[i]:=fumap[i];
fumax[i]:=max(fumax[i-1],fu[i]);
end;
fan[n]:=map[n]; fanmax[n]:=map[n];
fufan[n]:=fumap[n]; fufanmax[n]:=fumap[n];
for i:=n-1 downto 1 do begin
if fan[i+1]>=0 then fan[i]:=fan[i+1]+map[i]
else fan[i]:=map[i];
fanmax[i]:=max(fanmax[i+1],fan[i]);
if fufan[i+1]>=0 then fufan[i]:=fufan[i+1]+fumap[i] else fufan[i]:=fumap[i];
fufanmax[i]:=max(fufanmax[i+1],fufan[i]);
end;
maxans:=-maxlongint;
for i:=1 to n-1 do begin
temp:=zhengmax[i]+fanmax[i+1];
if temp>maxans then maxans:=temp;
temp:=fumax[i]+fufanmax[i+1];
if (sum+temp>maxans) and (sum+temp<>0) then
maxans:=sum+temp;
end;
writeln(maxans);
close(input); close(output); end.
最大子树和(maxsum3)
【问题描述】
小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。

一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题。

于是当日课后,小明就向老师提出了这个问题:
一株奇怪的花卉,上面共连有N 朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的。

每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的,说明这朵花看着都让人恶心。

所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。

经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。

老师的任务就是:通过
一系列“修剪”(也可以什么“修剪”都不进行),使剩下的那株(那朵)花卉上所有花朵的“美丽指数”之和最大。

老师想了一会儿,给出了正解。

小明见问题被轻易攻破,相当不爽,于是又拿来问你。

【输入文件】
输入文件maxsum3.in的第一行一个整数N(1 ? N ? 16000)。

表示原始的那株花卉上共N 朵花。

第二行有N 个整数,第I个整数表示第I朵花的美丽指数。

接下来N-1行每行两个整数a,b,表示存在一条连接第a 朵花和第b朵花的枝条。

【输出文件】
输出文件maxsum3.out仅包括一个数,表示一系列“修剪”之后所能得到的“美丽指数”之和的最大值。

保证绝对值不超过2147483647。

【样例输入】
5 7
-1 -1 -1 1 1 1 0
1 4
2 5
3 6
4 7
5 7
6 7
【样例输出】
3
【数据规模与约定】
对于60%的数据,有N?1000;
对于100%的数据,有N?16000。

题目大意:在一个无环无向图中(也可以叫树)删去一些边(及边上带的顶点),使剩下的顶点上的值最大。

树形DP。

设f[i]为取i这个顶点的美学最大值。

F[i]初始都为map[i],则对于所有与i相连的点f[j],如果f[j]>0就加入到f[i]否则不加。

注意f[j]不能再遍历i.最后max(f[i])即为所求。

var
ans,a,son,next,y:array[0..32001] of longint;
bb:array[0..16001] of boolean;
n,i,j,k,l,max:longint;
procedure maketree;
begin
assign(input,'maxsum3.in');
assign(output,'maxsum3.out');
reset(input); rewrite(output);
readln(n);
for i:=1 to n do begin read(a[i]); ans[i]:=a[i]; end;
readln;
l:=0; fillchar(son,sizeof(son),0);
fillchar(next,sizeof(next),0);
fillchar(y,sizeof(y),0);
for i:=1 to n-1 do begin
readln(j,k);
inc(l);
next[l]:=son[j];
y[l]:=k;
son[j]:=l;
inc(l);
next[l]:=son[k];
y[l]:=j;
son[k]:=l;
end;
end;
procedure tree(k:longint);
var i,j,erzi,bian:longint;
begin
bb[k]:=true;
bian:=son[k];
while bian<>0 do begin
erzi:=y[bian];
if bb[erzi]=false then begin
tree(erzi);
if ans[erzi]>0 then inc(ans[k],ans[erzi]); end;
bian:=next[bian];
end;
end;
begin
maketree;
fillchar(bb,sizeof(bb),false);
tree(1);
max:=0;
for i:=1 to n do if ans[i]>max then max:=ans[i]; writeln(max);
close(input); close(output);
end.。

相关文档
最新文档