夜未央Test1题解

T1 积木游戏             

     树状数组的一个简单应用,建立一个维护左节点的树状数组和一个维护右节点的树状数组,对于add操作,只要在维护左节点的树状数组l处加1,维护右节点的树状数组r处加1,那么询问[l,r]的答案就是左节点数组的r前缀和减去右节点数组的l-1前缀和。

var

  q,suml,sumr,i,j,k,l,r,m,n:longint;

  cl,cr:array[0..60005] of longint;



{file}

procedure openf;

begin

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

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

end;

procedure closef;

begin

  close(input); close(output);

  halt;

end;



{lowbit}

function lowbit(p:longint):longint;

begin

  exit(p and -p);

end;



{add}

procedure addl(x,num:longint);

begin

  while x<=n+1 do

  begin

    inc(cl[x],num);

    x:=x+lowbit(x);

  end;

end;

procedure addr(x,num:longint);

begin

  while x<=n+1 do

  begin

    inc(cr[x],num);

    x:=x+lowbit(x);

  end;

end;



{get}

procedure getsuml(x:longint);

begin

  suml:=0;

  while x>0 do

  begin

    inc(suml,cl[x]);

    x:=x-lowbit(x);

  end;

end;

procedure getsumr(x:longint);

begin

  sumr:=0;

  while x>0 do

  begin

    inc(sumr,cr[x]);

    x:=x-lowbit(x);

  end;

end;



begin

  {input}

  openf;

  readln(n,m);

  

  {doit}

  for i:=1 to m do

  begin

    readln(q,l,r);

    if q=1 then begin

      addl(l,1);

      addr(r,1);

    end;

    if q=2 then begin

      getsuml(r);

      getsumr(l-1);

      writeln(suml-sumr);

    end;

  end;

  closef;

end.
View Code 1
#include<iostream>

#include<cstdio>

#define lowbit(x) x&(-x)

using namespace std;



int q,i,j,k,l,r,m,n;

int cl[60005],cr[60005];



//file

void openf()

{

  freopen("block.in","r",stdin);

  freopen("block.out","w",stdout);

}

void closef()

{

  fclose(stdin); fclose(stdout);

}



//INT

int INT() 

{

  int res;

  char ch;

  while (ch = getchar(), !isdigit(ch));

  for (res = ch - '0'; ch = getchar(), isdigit(ch);)

  res = res * 10 + ch - '0';

  return res;

}

 

//add

void addl(int x,int num)

{

  for (; x<=n+1; x+=lowbit(x)) cl[x]+=num;

}

void addr(int x,int num)

{

  for (; x<=n+1; x+=lowbit(x)) cr[x]+=num;

}



//get

int suml(int x)

{

  int sum = 0;

  for (; x; x-=lowbit(x)) sum+=cl[x];

  return sum;

}

int sumr(int x)

{

  int sum = 0;

  for (; x; x-=lowbit(x)) sum+=cr[x];

  return sum;

}



int main()

{

  //input

  openf();

  n = INT();

  m = INT();

  

  //doit

  for (i = 1; i<=m; i++)

  {

    q = INT();

    l = INT();

    r = INT();

    if (q==1) 

    {

      addl(l,1);

      addr(r,1);

    }else printf("%d\n",suml(r)-sumr(l-1));

  }

  closef();

  return 0;

}  
View Code 2

 

T2 数字游戏             

     这道题首先要做到的就是如何确定方程,由于按照顺序输出,所以我们假定x1<=x2<=x3<=……<=xn,那么我们先将a排序,由于x1+x2是最小的,所以就是a1,同理x1+x3第二小,为a2,但是需要注意的是x2+x3不一定是第三小的,有可能x1+xk比其小,所以我们从a3开始,一个一个假定为x2+x3,联立之前的几个方程,解出x1,x2,x3,然后如果是负数或是无解则跳过,若解出,将x1+x2,x1+x3,x2+x3的结果从a数组中去掉,然后剩下最小的就一定是x1+x4,于是解出x4,之后如上去掉x4与之前几个解的和,剩下最小的是x1+x5,依次做下去,如果其中一个解为负,则该情况不成立,直到所有解解出,输出即可。

      用样例小小解释一下,a数组排序后为{1,2,3,4,5,6},则x1+x2=1,x1+x3=2,假设x2+x3=3解得x1=0,所以x2=1,x3=2,去掉1,2,3,集合为{4,5,6},则x4+x1为4,x4=4,去除4,5,6,集合为空,所以解成立,输出0,1,2,4。

var

  bo:boolean;

  q,i,j,k,l,m,n,tot:longint;

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

  x:array[0..100005] of longint;



{file}

procedure openf;

begin

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

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

end;

procedure closef;

begin

  close(input); close(output);

  halt;

end;



{sort}

procedure qsort(l,r:longint);

var

  i,j,mid,t:longint;

begin

  i:=l; j:=r;

  mid:=b[l+random(r-l+1)];

  repeat

    while b[i]<mid do inc(i);

    while b[j]>mid do dec(j);

    if i<=j then begin

      t:=b[i];

      b[i]:=b[j];

      b[j]:=t;

      inc(i); dec(j);

    end;

  until i>j;

  if i<r then qsort(i,r);

  if l<j then qsort(l,j);

end;



begin

  {input}

  openf;

  readln(n);

  n:=n*(n-1) div 2;

  for i:=1 to n do

  read(b[i]);

  randomize;

  qsort(1,n);



  {doit}

  for i:=3 to n do

  begin

    bo:=true;

    move(b[1],a[1],n*sizeof(b[1]));

    x[1]:=(a[1]+a[2]-a[i]);

    if x[1]<0 then continue;

    if x[1] mod 2=0 then

    begin

      x[1]:=x[1] div 2;

      x[2]:=a[1]-x[1];

      if x[2]<0 then continue;

      x[3]:=a[i]-x[2];

      if x[3]<0 then continue;

    end

    else continue;

    a[1]:=0; a[2]:=0;

    a[i]:=0;

    tot:=3;

    for j:=3 to n do

    if a[j]<>0 then

    begin

      inc(tot);

      x[tot]:=a[j]-x[1];

      if x[tot]<0 then begin

        bo:=false;

        break;

      end;

      k:=1;

      for l:=j to n do

      if a[l]=x[tot]+x[k] then

      begin

        a[l]:=0;

        inc(k);

        if k=tot then break;

      end;

      if k<>tot then bo:=false;

    end;

    if bo then begin

      for l:=1 to tot do

      write(x[l],' ');

      closef;

    end;

  end;



  {closef}

  writeln('No solution');

  closef;

end.
View Code 1
#include <iostream> 



using namespace std;



bool bo;

int q,i,j,k,l,m,n,tot;

int b[5001],a[5001];

int x[100005];



//file

void openf()

{

  freopen("math.in","r",stdin);

  freopen("math.out","w",stdout);

}

void closef()

{

  fclose(stdin); fclose(stdout);

}



//INT

int INT() 

{

  int res;

  char ch;

  while (ch = getchar(), !isdigit(ch));

  for (res = ch - '0'; ch = getchar(), isdigit(ch);)

  res = res * 10 + ch - '0';

  return res;

}



//sort

void qsort(int l,int r)

{

  int i,j,t,mid;

  mid = b[(l+r)>>1];

  i = l; j = r;

  do {

    while (b[i]<mid) i++;

    while (b[j]>mid) j--;

    if (i<=j) 

    { 

      t = b[i];

      b[i] = b[j];

      b[j] = t;

      i++; j--;

    }   

  }

  while (i<=j);

  if (i<r) qsort(i,r);

  if (l<j) qsort(l,j);

}



int main()

{

  int step = 0;

  //input

  openf();

  n = INT();

  n = n * (n - 1) / 2;

  if (n==1) 

  {

    cout<<"No solution";

    closef();

    return(0);

  }

  for (i=1; i<=n; i++)

    b[i] = INT();

  qsort(1,n);

  //doit

  for (i=3; i<=n; i++)

  { 

    bo = true;

    for (j=1; j<=n; j++)

    a[j] = b[j];

    x[1] = (a[1]+a[2]-a[i]);

    if (x[1]<0) continue;

    if (x[1]%2==0) 

    {

      x[1] /= 2;

      x[2] = a[1]-x[1];

      if (x[2]<0) continue;

      x[3] = a[i]-x[2];

      if (x[3]<0) continue;

    }

    else continue;

    a[1] = 0; a[2] = 0;

    a[i] = 0;

    tot = 3;

    for (j=3; j<=n; j++)

    if (a[j]!=0)

    {

      x[++tot] = a[j]-x[1];

      if (x[tot]<0)

      {

        bo = false;

        break;

      }

      k = 1;

      for (l=j; l<=n; l++)

      if (a[l] == x[tot]+x[k])

      {

        a[l] = 0;

        k++;

        if (k == tot) break;

      }

      if (k!=tot) bo = false;

    }

    if (bo)

    {

      for (l=1; l<=tot; l++)

      printf("%d ",x[l]);

      //system("pause");

      closef;

      return 0;

    }

  }

  

  cout<<"No solution";

  closef();

  return 0;

}

  
View Code 2

 

T3 造梦                     

     分析题目,可得一个很显然的贪心,所有石柱相差不超过5那么全部一样是最优的,因为最终高度取决于最短的石柱,然后如何去求这个统一高度呢?我们可以这样设想,如果知道了这个需要的高度,那么验证是否可以达到是不是就非常简单了,只要将每一块石料除以已知高度加到ans上,看是否达到需要的块数就可以了。那么,二分检索的模型就浮出水面了,我们取最长石料为右端点,1为左端点,每一次取中点检验是否可行,然后根据单调性更新左右端点,就可以简单地完成这道题了。

var

  l,r,ans,mid,cnt,i,j,k,m,n:longint;

  a:array[0..1000005] of longint;



{file}

procedure openf;

begin

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

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

end;

procedure closef;

begin

  close(input); close(output);

  halt;

end;



{check}

function check(x:longint):boolean;

begin

  cnt:=0;

  for i:=1 to m do

  begin

    inc(cnt,a[i] div x);

    if cnt>=n then exit(true);

  end;

  exit(false);

end;



begin

  {input}

  openf;

  readln(m,n);



  {doit}

  for i:=1 to m do

  begin

    read(a[i]);

    if a[i]>r then r:=a[i];

  end;

  l:=1;

  repeat

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

    if check(mid) then begin

      ans:=mid;

      l:=mid+1;

    end

    else r:=mid-1;

  until l>r;



  {output}

  writeln(ans);

  closef;

end.
View Code 1
#include <iostream> 

#include <cstdio>



using namespace std;



const int size=1000005;



int l,r,ans,mid,cnt,i,j,k,m,n;

int a[size];



//file

void openf()

{

  freopen("build.in", "r", stdin);

    freopen("build.out", "w", stdout);

}

void closef()

{

  fclose(stdin); fclose(stdout);

}



//check

bool check(int x)

{

  cnt = 0;

  for (i = 0; i < m; i++)

  {

    cnt+=(a[i] / x);

    if (cnt >= n) return(true);

  }

  return(false);

}



//INT

int INT() 

{

  int res;

  char ch;

  while (ch = getchar(), !isdigit(ch));

  for (res = ch - '0'; ch = getchar(), isdigit(ch);)

  res = res * 10 + ch - '0';

  return res;

}



//main

int main()

{  

  openf();

  m = INT();

  n = INT();

  

  for (i = 0; i < m; i++)

  {

    a[i] = INT();

    if (a[i] > r) r = a[i];

  }

  l = 1;

  do

  {

    mid = (l + r) >> 1;

    if (check(mid)) 

    {

      ans = mid;

      l = mid + 1;

    }

    else r = mid-1;

  }

  while (l <= r);

  

  printf("%d",ans);

  //system("pause");

  closef;

  return(0);

}

  
View Code 2

 

夜未央Test1标程 

你可能感兴趣的:(test)