【USACO题库】1.4.3 Arithmetic Progressions等差数列(模拟)

来源:互联网 发布:透明名片生成器软件 编辑:程序博客网 时间:2024/05/21 00:48

【题目】

一个等差数列是一个能表示成a, a+b, a+2b,..., a+nb (n=0,1,2,3,...)
在这个问题中a是一个非负的整数,b是正整数。
写一个程序来找出在双平方数集合S中长度为n的等差数列。
双平方数集合是所有能表示成p2q2的数的集合。

输入

第一行:N(3<= N<=25),要找的等差数列的长度。第二行:M(1<= M<=250),搜索双平方数的上界0 <= p,q <= M。

样例输入

5
7

输出
如果没有找到数列,输出`NONE'。
如果找到了,输出一行或多行, 每行由于二个整数组成:a,b
这些行应该先按b排序再按a排序。
将不会有只多于10,000个等差数列。

样例输出
1 4
37 4
2 8
29 8
1 12
5 12
13 12
17 12
5 20
2 24

【解题思路】

    这道题十分容易超时。我们一开始先对所有可能产生的等差数列的每一个数进行标记,可组成为true,反之为false。之后我们枚举开头结尾,判断等差数列即可,有个小优化(如果最大的等差数列比125000大,就直接返回false),之后排序输出即可。

【代码实现】

<span style="font-size:14px;">var         i,j,n,m,num:longint;         a:array[0..125000] of boolean;         s:array[0..100000,1..2] of longint;procedure q(l,r:longint);//输出时排序的var         i,j,m1,m2,p:longint;begin         i:=l;         j:=r;         m1:=s[(l+r) div 2,2];         m2:=s[(l+r) div 2,1];         while i<j do         begin                  while (s[i,2]<m1)or((s[i,1]<m2)and(s[i,2]=m1)) do inc(i);                  while (s[j,2]>m1)or((s[j,1]>m2)and(s[j,2]=m1)) do dec(j);                  if i<=j then                  begin                           p:=s[i,2];                           s[i,2]:=s[j,2];                           s[j,2]:=p;                           p:=s[i,1];                           s[i,1]:=s[j,1];                           s[j,1]:=p;                           inc(i);                           dec(j);                  end;         end;         if l<j then q(l,j);         if i<r then q(i,r);end;function pd(x,y:longint):boolean;//判断等差的var         i:longint;begin         if (x+y*(n-1)>125000)or(a[x+y*(n-1)]=false) then//如果最后一个大于125000或者最后一个不符合条件,就不可以了                  exit(false);         for i:=1 to n-1 do                  if a[x+y*i]=false then                           exit(false);         exit(true);end;begin         readln(n,m);         for i:=0 to m do                  for j:=0 to m do                           a[i*i+j*j]:=true;//提前判断处理好双平方数         for i:=0 to m*m do         begin                  if a[i]=false then continue;//如果第一个都不是了,那就不可能了                  for j:=1 to (m*m*2) div (n-1) do//这个是一个公式,是范围的                           if pd(i,j) then//判断是不是合法的等差数列                           begin                                    inc(num);                                    s[num,1]:=i;                                    s[num,2]:=j;//记录                           end;         end;         if num=0 then         begin                  writeln('NONE');                  halt;         end;//没有的情况         q(1,num);         for i:=1 to num do                  writeln(s[i,1],' ',s[i,2]);//输出end.</span>
0 0
原创粉丝点击