1. 题目
1. 数字查找
(find.pas/c/cpp)
【题目描述】
X和Y在玩一个非常有意思的游戏,X在纸上写了n个数字,然后X向Y提一些问题,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<=100,1<=m<=50,k<=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.