USACO 1.4.4 Arithmetic Progressions

原文翻译:

翻译者:timgreen

转载自:OIBH

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

PROGRAM NAME: ariprog

INPUT FORMAT

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

SAMPLE INPUT (file ariprog.in)
5
7

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

SAMPLE OUTPUT (file ariprog.out)
1 4
37 4
2 8
29 8
1 12
5 12
13 12
17 12
5 20
2 24


Hash+搜索的时候要注意剪枝


USER: A e [chenh193]
TASK: ariprog
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.000 secs, 9716 KB]
   Test 2: TEST OK [0.000 secs, 9720 KB]
   Test 3: TEST OK [0.000 secs, 9720 KB]
   Test 4: TEST OK [0.022 secs, 9716 KB]
   Test 5: TEST OK [0.000 secs, 9720 KB]
   Test 6: TEST OK [0.043 secs, 9716 KB]
   Test 7: TEST OK [0.324 secs, 9716 KB]
   Test 8: TEST OK [0.637 secs, 9720 KB]
   Test 9: TEST OK [0.540 secs, 9716 KB]

All tests OK.

Your program ('ariprog') produced all correct answers! This is your submission #9 for this problem. Congratulations!


第8组数据几乎是极限数据了,没优化以前>5s.优化以后0.6x秒就过了...



  1. /*
  2. ID: chenh193
  3. PROG: ariprog
  4. LANG: C++
  5. */
  6. #include<iostream>
  7. #include<algorithm>
  8. using namespace std;
  9. //hash
  10. const int SIZE=524288;
  11. const int BUF=5000;
  12. //record
  13. struct rec
  14. {
  15.     int a,b;
  16.     bool operator<(const rec & o)const{return b<o.b||(b==o.b&&a<o.a);}
  17. }r[10001];
  18. struct Hash
  19. {
  20.     int a,b,next;
  21. }hash[SIZE+BUF];
  22. bool dbit[251*251*2],flag[SIZE];
  23. int M,N,ULimit,Rlen=0,table[22000],Tlen=0,buf=SIZE;
  24. void inhash(int a,int b)
  25. {
  26.     int key=((a+b)&(SIZE-1));
  27.     if(!flag[key])
  28.     {
  29.         hash[key].a=a;
  30.         hash[key].b=b;
  31.         hash[key].next=-1;
  32.         flag[key]=true;
  33.         return;
  34.     }
  35.     while(key!=-1)
  36.     {
  37.         if(hash[key].a==a&&hash[key].b==b)
  38.             return;
  39.         if(hash[key].next==-1)
  40.             break;
  41.         key=hash[key].next;
  42.     }
  43.     hash[key].next=++buf;
  44.     hash[buf].a=a;
  45.     hash[buf].b=b;
  46.     hash[buf].next=-1;
  47.     return;
  48. }
  49. bool isinhash(int a,int b)
  50. {
  51.     int key=((a+b)&(SIZE-1));
  52.     if(!flag[key]) return false;
  53.     while(key!=-1)
  54.     {
  55.         if(hash[key].a==a&&hash[key].b==b)
  56.             return true;
  57.         if(hash[key].next==-1)
  58.             break;
  59.         key=hash[key].next;
  60.     }
  61.     return false;
  62. }
  63. void dfs()
  64. {
  65.     int i,j,k,LLimit=ULimit/(N-1),ta,tb,tmp,times;
  66.     for(i=0;i<Tlen;i++)
  67.         for(j=i+1;j<Tlen;j++)
  68.         {
  69.             if((tb=table[j]-table[i])>LLimit)break;
  70.             ta=table[i];
  71.             if((tmp=ta+(N-1)*tb)>ULimit||!dbit[tmp])continue;
  72.             if(isinhash(ta,tb))continue;
  73.             times=0;
  74.             for(k=ta;k<=ULimit;k+=tb)
  75.             {
  76.                 if(!dbit[k])
  77.                     break;
  78.                 times++;    
  79.             }
  80.             if(times>=N)
  81.             {
  82.                 times=times-N+1;
  83.                 tmp=ta;
  84.                 for(k=1;k<=times;k++)
  85.                 {
  86.                     r[Rlen].a=tmp;
  87.                     r[Rlen].b=tb;
  88.                     inhash(r[Rlen].a,r[Rlen].b);
  89.                     Rlen++;
  90.                     tmp+=tb;
  91.                 }
  92.             }
  93.         }
  94. }
  95. int main()
  96. {
  97.     int p,q,i;
  98.     scanf("%d%d",&N,&M);
  99.     for(p=0;p<=M;p++)for(q=0;q<=M;q++)dbit[p*p+q*q]=true;
  100.     ULimit=2*M*M;
  101.     for(i=0;i<=ULimit;i++)if(dbit[i])table[Tlen++]=i;
  102.     dfs();
  103.     sort(r,r+Rlen);
  104.     for(i=0;i<Rlen;i++)
  105.         printf("%d %d/n",r[i].a,r[i].b);
  106.     if(Rlen==0)
  107.         puts("NONE");
  108.     return 0;
  109. }

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值