USACO-Section1.4 Arithmetic Progressions【暴力枚举】

来源:互联网 发布:直播软件商业计划书 编辑:程序博客网 时间:2024/05/22 13:47

题目描述:

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

时间限制: 5 秒

INPUT FORMAT:

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

OUTPUT FORMAT:

(file ariprog.out)
如果没有找到数列,输出“NONE”。
如果找到了,输出一行或多行, 每行由二个整数组成:a,b。 a为等差数列的第一个值,b为等差数列的公差。
这些行应该先按b排序再按a排序。
所求的等差数列将不会多于10,000个。


SAMPLE INPUT

5
7


SAMPLE OUTPUT

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


解题思路:

这道题的主要思想就是暴力枚举,将所有的情况枚举出来并判断,难点就是如何剪枝。如果不剪枝的话第7组开始时间就超出了。我用a数组来保存所有的“bisquares”,通过模拟程序运行,我们会发现当当前等差数列的最后一项(a[i]+(a[j]-a[i])*(n-1))大于最大值时,j更大时不可能再有结果了(显而易见),通过这个思路可以减去大量的枝。下面是代码。

#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>int a[150000],v[150000],m,n;typedef struct Ans {    int x;    int y;} Ans;Ans ans[150000];int cmp(const void *p,const void *q){     Ans *pp=(Ans *)p;    Ans *qq=(Ans *)q;       return pp->y-qq->y;    }int acmp(const void *a,const void *b){    return *(int *)a-*(int *)b;} int main() {    FILE *fin  = fopen ("ariprog.in", "r");    FILE *fout = fopen ("ariprog.out", "w");    fscanf(fin,"%d",&n);    fscanf(fin,"%d",&m);    int i,j,k,count=0,count1=0;    for(i=0;i<=m;i++){//枚举所有bisquares,并定义哈希表        for(j=0;j<=m;j++){                  if(!v[i*i+j*j]){            a[count++]=i*i+j*j;            v[i*i+j*j]=1;        }        }    }    qsort(a,count,sizeof(a[0]),acmp);    for(i=0;i<count;i++){        for(j=i+1;j<count;j++){        if(a[i]+(a[j]-a[i])*(n-1)>m*m*2)break; //剪枝        for(k=n-1;k>=2;k--){//判断是否符合条件            if(!v[a[i]+(a[j]-a[i])*k])break;        }        if(k==1){            ans[count1].x=a[i];            ans[count1++].y=a[j]-a[i];        }    }    }    qsort(ans,count1,sizeof(ans[0]),cmp);    if(count1==0)fprintf(fout,"NONE\n");    else    for(i=0;i<count1;i++)    fprintf(fout,"%d %d\n",ans[i].x,ans[i].y);    exit(0);}