USACO-Chapter1-Section 1.4-Arithmetic Progressions (ariprog)

【题目描述】

      一个等差数列是一个能表示成a, a+b, a+2b,..., a+nb (n=0,1,2,3,...)的数列。

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

【输入格式】

第一行: N(3<= N<=25),要找的等差数列的长度。

第二行: M(1<= M<=250),搜索双平方数的上界0 <= p,q <= M。

【输出格式】

如果没有找到数列,输出`NONE'。

如果找到了,输出一行或多行, 每行由二个整数组成:a,b。

这些行应该先按b排序再按a排序。

【输入样例】

5
7

【输出样例】

1 4
37 4
2 8
29 8
1 12
5 12
13 12
17 12
5 20
2 24

【思路】

      先预处理,把所有的双平方数存入数组中,可以在O(1)时间内check结果,然后枚举bb,aa。先是bb后是aa。这样输出免去了排序(此算法会在枚举过程中费时间)然后各种乱搞就行了。

【附上秒杀思路】

      这道题就是暴力搜索,时限是5s,方法是很简单的:枚举所有的可能解,注意剪枝。

但是在编程细节上要注意,很多时候你的程序复杂度没有问题,但常数过大就决定了你的超时(比如说,你比别人多赋值一次,这在小数据时根本没有区别,但对于1个运行5s的大数据,你可能就要用10s甚至更多)。

具体来说,预处理把所有的bisquare算出来,用一个布尔数组bene[i]记录i是否是bisquare 另外为了加速,用list记录所有的bisquare(除去中间的空位置,这在对付大数据时很有用),list中的数据要有序。

然后枚举list中的数,把较小的作为起点,两数的差作为公差,接下来就是用bene判断是否存在n个等差数,存在的话就存入path中,最后排序输出。 此时缺少重要剪枝,会超时

思考程序发现,费时最多的地方是枚举list中的数,所以对这个地方的代码加一些小修改,情况就会不一样:

  1. 在判断是否存在n个等差数时,从末尾向前判断(这个不是主要的)。
  2. 在枚举list中的数时,假设为i,j,那么如果list[i]+(list[j]-list[i])×(n-1)>lim(lim是最大可能的bisquare),那么对于之后的j肯定也是大于lim的,所以直接break掉。(这个非常有效)

AC,最大数据0.464s(如果是PASCAL的话应该还不止。请看C++的GPF的程序)。

其实输出时可以不用排序,用一个指针b[i]存公差为i的a的链表,由于搜索时a是有序的,存到b[i]中也应是有序的,这样就可以直接输出。对极限数据b的范围应该不超过m^2/n=2500,即b:array[1..2500]of point; 而如果qsort的话,复杂度为n*logn,n<=10,000

枚举a,b也可以过的 。。要加几个小优化

【代码】

  • Executing...
  • Test 1: TEST OK [0.000 secs, 764 KB]
  • Test 2: TEST OK [0.000 secs, 764 KB]
  • Test 3: TEST OK [0.000 secs, 764 KB]
  • Test 4: TEST OK [0.000 secs, 764 KB]
  • Test 5: TEST OK [0.011 secs, 764 KB]
  • Test 6: TEST OK [0.140 secs, 764 KB]
  • Test 7: TEST OK [1.739 secs, 764 KB]
  • Test 8: TEST OK [3.953 secs, 764 KB]
  • Test 9: TEST OK [3.467 secs, 764 KB]
  • All tests OK.
{
 ID  : c_CaM.19
 LANG: PASCAL
 TASK: ariprog
}
Program CaM(input,output);
Var
  f:array[0..500000] of boolean;
  ans,tot,i,aa,bb,node,j,n,m:longint;
  flag:boolean;

Procedure innt;
Begin
  assign(input,'ariprog.in'); reset(input);
  assign(output,'ariprog.out'); rewrite(output);
End;

Procedure outt;
Begin
  close(input);
  close(output);
End;

Begin
  innt;
  readln(n); readln(m);
  for i:=0 to m do
    for j:=0 to m do
      f[i*i+j*j]:=true;

  for bb:=1 to (m*m div (n-1))+n*3 do
    for aa:=0 to m*m-(m*m div (n-1)) do
    Begin
      flag:=false; tot:=0;
      for i:=0 to n-1 do
      Begin
        node:=aa+i*bb;
        if f[node]=false then break;
        inc(tot);
      End;
      if tot=n then
      Begin
        writeln(aa,' ',bb);
        inc(ans);
      End;
    End;
  if ans=0 then writeln('NONE');
  outt;
End.
posted @ 2012-03-05 00:08  你滴韩王  阅读(344)  评论(0)    收藏  举报