zoukankan      html  css  js  c++  java
  • 夜未央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
    ",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标程 

    愿你出走半生,归来仍是少年

  • 相关阅读:
    对话框
    枚举、联合
    WinCE 应用程序开机自启动方法
    调用directshow出现链接错误
    修改了WINCE自带的驱动程序后如何编译
    如何设置WINCE系统字体、字号?如何设置自己开发的软件的字体、字号
    在不采用硬件计时器的情况下如何创建更精确的计时器
    驱动程序如何发通知给应用程序
    如何得到WAV文件播放的总时间
    解决CE6和CE5在Platform Builder的Connectivity Options上的冲突
  • 原文地址:https://www.cnblogs.com/forever97/p/3438137.html
Copyright © 2011-2022 走看看