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中的数,所以对这个地方的代码加一些小修改,情况就会不一样:
- 在判断是否存在n个等差数时,从末尾向前判断(这个不是主要的)。
- 在枚举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.
浙公网安备 33010602011771号