解题报告 数学2

2、数学,又是数学(mathagain)

其实吧,大家也发现了,这六道题本来是一科一道的,但是呢,由于某某人比较……,就不顾某某人的反对抛弃了我们可爱的English,又出了一道math……

题目描述

  Liukeke同学(我们敬爱滴亲爱滴可爱滴班长大人)最近又在忙着开班会(真是个工作狂),于是乎,数学学案就被抛到了九霄云外,直到预备铃打完,他才发现那张美丽的雪白的学案,眼看一场血案即将发生,他请你用最快的速度帮他算完第一题:

给定一个数串,数串的长度为n,现在将一个子串的每个数字之和定义为该子串的数串和,请你求出数串中有多少个子串的数串和为正数。

输入格式

第一行一个数n,表示数串的长度。

第二行一共n个数,表示数串中的每个数

输出格式

 就一个数,表示数串中有多少个子串的数串和为正数。

样例输入

3

8 -9 2

样例输出

3

数据范围

30%   n<=1000。

100%  n<=100000。

 

Liukeke 的学科试题之五·数学2。(因为此人实在不知道怎么出英语了,⊙﹏⊙b

 

预处理出累和,不难发现,只要前一个和小于后一个,这两个的差所表示的那一段数列的和就是正数。

 

然后,就对累和的那个数列归并求顺序对。好吧,我承认我当时把这个算法给忘了。

 

代码(Liukeke

var

 a,b:array[0..100000] of longint;

  i,n,t:longint;ans:int64;

 

procedure merge(l,r:longint);

var mid,i,j,k:longint;

begin

 if l=r then exit;

 mid:=(l+r)>>1;

 merge(l,mid);merge(mid+1,r);

 i:=l; j:=mid+1; k:=l;

 while (i<=mid) and(j<=r) do

  begin

   if a[i]>=a[j] then begin inc(ans,i-l);b[k]:=a[j];inc(k);inc(j);end

   else begin b[k]:=a[i]; inc(k);inc(i);end;

  end;

 if i<=mid then for j:=i to mid do

                 begin

  b[k]:=a[j];inc(k);

 end

 else for i:=j to r do

       begin

    b[k]:=a[i];inc(k);

inc(ans,mid-l+1);

   end;

 for i:=l to r do a[i]:=b[i];

end;

 

begin

assign(input,'mathagain.in');reset(input);

assign(output,'mathagain.out');rewrite(output);

 readln(n);

 fillchar(a,sizeof(a),0);

 for i:=1 to n do

  begin

   read(t);

   a[i]:=t+a[i-1];

  end;

 merge(0,n);

 writeln(ans);

 close(input);close(output);

end.

 

 

 

 

 

补充:归并求逆序对。

type
arr=array[0..40000] of longint;
var
temp,a,b:arr;
c:array[0..200,0..200] of longint;
i,j,k,m,n,ans1,ans2:longint;
procedure hba(l,mid,r:longint);
var
i,j,k,kk:longint;
begin
i:=l; j:=mid+1;
for kk:=l to r do
    begin
      if (i<=mid)and((a[i]<=a[j])or(j>r)) then
        begin
          temp[kk]:=a[i];
          inc(i);
        end
      else
        begin
          temp[kk]:=a[j];
          inc(j);
          if i<mid+1 then inc(ans1,mid-i+1);
        end;
    end;
for kk:=l to r do
    a[kk]:=temp[kk];
end;

procedure mergea(s,t:longint);
var
k:longint;
begin
if s=t then exit;
k:=(s+t)>>1;
if k>s then mergea(s,k);
if t>k+1 then mergea(k+1,t);
hba(s,k,t);
end;

procedure hbb(l,mid,r:longint);
var
i,j,k,kk:longint;
begin
i:=l; j:=mid+1;
for kk:=l to r do
    begin
      if (i<=mid)and((b[i]<=b[j])or(j>r)) then
        begin
          temp[kk]:=b[i];
          inc(i);
        end
      else
        begin
          temp[kk]:=b[j];
          inc(j);
          if i<mid+1 then inc(ans2,mid-i+1);
        end;
    end;
for kk:=l to r do
    b[kk]:=temp[kk];
end;

procedure mergeb(s,t:longint);
var
k:longint;
begin
if s=t then exit;
k:=(s+t)>>1;
if k>s then mergeb(s,k);
if t>k+1 then mergeb(k+1,t);
hbb(s,k,t);
end;

begin
assign(input,'game.in'); reset(input);
assign(output,'game.out'); rewrite(output);
while not eof do
begin
readln(n,m);
for i:=1 to n do
    begin
      for j:=1 to n do read(c[i,j]);
      readln;
    end;
if odd(m) then
   begin
    for i:=1 to n do
      for j:=1 to n do
        a[(i-1)*n+j]:=c[i,j];
    for j:=1 to n do
      for i:=1 to n do
        b[(j-1)*n+i]:=c[i,j];
   end
else
    begin
      for i:=1 to n do
        for j:=1 to n do
           b[(i-1)*n+j]:=c[i,j];
      for j:=1 to n do
        for i:=1 to n do
           a[(j-1)*n+i]:=c[i,j];
    end;
ans1:=0; ans2:=0;
mergea(1,n*n);
mergeb(1,n*n);
if ans1=ans2 then
    writeln('NYY and XYY will try again')
else
if ans1<ans2 then
    writeln('NYY wins the Rocket''s Game')
else
    writeln('XYY wins the Rocket''s Game');
writeln;
end;
close(input); close(output);
end.

注:题目中要求求两遍逆序对,就是用归并排序做。需要注意的点:在处理的数据比较多的时候不要再合并时fillchar temp,在递归的时候判断一下大小(红的地方),不然可能栈溢出。

 

posted @ 2011-10-25 15:23  木小漾  阅读(375)  评论(0编辑  收藏  举报