[USACO1.4]等差数列 Arithmetic Progressions
题目
题目描述
一个等差数列是一个能表示成a, a+b, a+2b,..., a+nb (n=0,1,2,3,...)的数列。
在这个问题中a是一个非负的整数,b是正整数。写一个程序来找出在双平方数集合(双平方数集合是所有能表示成p的平方 + q的平方的数的集合,其中p和q为非负整数)S中长度为n的等差数列。
输入输出格式
输入格式:
第一行: N(3<= N<=25),要找的等差数列的长度。
第二行: M(1<= M<=250),搜索双平方数的上界0 <= p,q <= M。
输出格式:
如果没有找到数列,输出`NONE'。
如果找到了,输出一行或多行, 每行由二个整数组成:a,b。
这些行应该先按b排序再按a排序。
所求的等差数列将不会多于10,000个。
输入输出样例
题目大意
题目刚开始我也看不懂
后来懂了。。。
其实就是在一个数列里找到长度为n的等差数列
这个数列是(0到m)平方加上 (0到m)平方形成的所有的数
输出第一个数的数值和公差即可
分析
首先,当然是构建数列啦
然后我们就要找等差数列啦
等差数列从何入手呢?
等差数列顾名思义是有一个公差的
我们只需要枚举公差就好了
于是我们通过枚举前两的在等差数列的数得到公差后
向后查找其他数
最后如果所有数存在就可以算一种了
排序 就可以输出啦
还有一个要注意的:
一个很重要的优化点
当数很多,公差很大时
显然超时
所以我们在查找前要加判断
当 第一个数+(n-2)*公差>最大值时 break
因为是有序的,当出现第一个大于最大值时,后面都不行
代码
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int a[62500000],b[62500000]; 5 struct sb 6 { 7 int shu,cha; 8 }ans[600000]; 9 bool cmp(sb a,sb b) 10 { 11 if (a.cha<b.cha) return true; 12 if (a.cha==b.cha) 13 if (a.shu<b.shu) return true; 14 return false; 15 } 16 int main () 17 { 18 int n,m; 19 cin>>n>>m; 20 int k=1; 21 for (int i=0;i<=m;i++) // 得到数列 22 for (int j=i;j<=m;j++) 23 { 24 a[i*i+j*j]=1; 25 b[k++]=i*i+j*j; 26 } 27 sort(b+1,b+1+k); //排序 28 int wz=unique(b+1,b+1+k)-b; //因为会有重复,所以去重 29 k=1; 30 for (int i=1;i<=wz;i++) 31 { 32 for (int j=i+1;j<=wz;j++) 33 { 34 int ca=b[j]-b[i],bj=0; 35 if (ca<=0) continue; 36 if (b[j]+(n-2)*ca>2*m*m) break; //优化 37 for (int ii=1;ii<=n-2;ii++) 38 { 39 if (a[b[j]+ii*ca]!=1) 40 { 41 bj=1; 42 break; 43 } 44 } 45 if (bj==0) { 46 ans[k].shu=b[i]; 47 ans[k].cha=ca; 48 k++; 49 } 50 } 51 } 52 sort(ans+1,ans+1+k,cmp); //排序输出 53 if (k<2) cout<<"NONE"; 54 for (int i=2;i<=k;i++) 55 cout<<ans[i].shu<<" "<<ans[i].cha<<endl; 56 }
为何要逼自己长大,去闯不该闯的荒唐