解题报告 数字查找

1.        题目

1. 数字查找

    find.pas/c/cpp

【题目描述】

XY在玩一个非常有意思的游戏,X在纸上写了n个数字,然后XY提一些问题,Y来回答。

“你知道这些数字中两两结合组成的和不超过M1的有多少种吗?”

“这太简单了!有K1种!”

“你知道这些数字中两两结合组成的和不超过M2的有多少种吗?”

“这太简单了!有K2种!”

“你知道这些数字中两两结合组成的和不超过M3的有多少种吗?”

“这太简单了!有K3种!”

“你知道……”

“烦不烦!不知道!”

就这样,Y怒了。

但是Y仔细一想,不能和X一般见识,但是又不愿意回答如此单调的问题。所以Y请你来帮忙。

 

【输入格式】

第一行一个数n,表示数字的个数;

第二行到第n+1行,每行一个不超过2,000,000,000的数k

n+2行一个数m,表示m个问题;

n+3行到第n+m+2行,每行一个数M,询问表示n中两两组合不超过M的组合的个数;

 

【输出格式】

输出m行,每行对应一个答案

 

【输入样例】

3

1

2

3

2

2

3

 

【输出样例】

0

1

 

【数据范围】

30%的数据1<=n<=1001<=m<=50k<=2000;

100%的数据 1<=n<=10000, 1<=m<=100,k<=2,000,000,000;

 

2.        算法

过掉他,有两种途径:

二分,不解释。

先排序,然后左端点枚举,右端点一直向右走.......

 

越说越乱,继续上代码。

(怎么我的语文越来越不好了?)

3.        注意事项

枚举是要优化的。

觉得第二种不保险就打二分吧。

4.        代码

二分 (Leve)

var

 n,i,j,l,r,mid,op,mm,ii,ans:longint;

 m:int64;

 a:array[1..10000] of int64;

procedure qs(r,l:longint);

 var

  i,j:longint;

  x,y:int64;

 begin

  i:=r; j:=l;

  x:=a[(i+j)>>1];

  repeat

   while a[i]<x do inc(i);

   while a[j]>x do dec(j);

    if i<=j then

 begin

  y:=a[i];

  a[i]:=a[j];

  a[j]:=y;

  inc(i);

  dec(j);

 end;

  until i>j;

 if i<l then qs(i,l);

 if j>r then qs(r,j);

end;

begin

 assign(input,'find.in');

 assign(output,'find.out');

 reset(input);

 rewrite(output);

 readln(n);

 for i:=1 to n do

  readln(a[i]);

 qs(1,n);

 readln(mm);

 for ii:=1 to mm do

  begin

   readln(m);

   ans:=0;

   for i:=1 to n do

    begin

 l:=i+1; r:=n;

         op:=0;

 while l<=r do

  begin

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

   if a[i]+a[mid]<=m then

    begin

 op:=mid;

 l:=mid+1;

end

else

r:=mid-1;

   end;

         if op>i then

 ans:=ans+op-i;

   end;

  writeln(ans);

  end;

  close(input);

  close(output);

end.

 

 

 

枚举优化 (SueMiller)

var n:longint;

    a:array[0..10001]of int64;

    i,j,k:longint;

    m,l,r,mid,ans:longint;

    mm:double;

    x:int64;

 

procedure quicksort(l,r:longint);

var i,j:longint;x,y:int64;

begin

 i:=l; j:=r; x:=a[(l+r)>>1];

 repeat

  while a[i]<x do inc(i);

  while x<a[j] do dec(j);

  if i<=j then

   begin

   y:=a[i]; a[i]:=a[j]; a[j]:=y;

   inc(i); dec(j);

   end;

 until i>j;

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

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

end;

 

begin

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

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

 

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

  readln(n);

  for k:=1 to n do

    readln(a[k]);

 

  quicksort(1,n);

 

  readln(m);

  for k:=1 to m do

    begin

      readln(x);

      r:=n;

      ans:=0;

      for l:=1 to n do

        begin

          while a[l]+a[r]>x do dec(r);

          if r<l then break;

          ans:=ans+r-l;

        end;

      writeln(ans);

    end;

  close(input);close(output);

end.

 

原文地址:https://www.cnblogs.com/SueMiller/p/2213452.html