题意:给出一个特殊构造的三角形,具体看原题的图,问从第i个三角形到第j个三角形最少经过的边数。

题解:对于这种一看就知道通过推数学公式做的题重点就在如何推出公式:

   1、先把题目中不必要的东西都去掉,三角形放在那干啥?还是去掉吧,将它变成

      1

      3

    2    4

    6    8

  5    7    9

  11   13   15

  ........

即根据三角形的位置与他们相连的情况化成上面,只有相邻的至多三个点与某个点相连

   2、观察上面第2i-1行,它的末尾都为i^2,含i个数,且它的下一行都是i^2+2k的形式。

   3、将问题变一下,给出任意一个n可以利用第2点快速算出它是位于图中的第几大行(这里以两小行为一大行),第几列。

   4、对于题目给出的两个点,我们算出它们各自是第几行,第几列,并且属于第几小行。然后,同属于一种小行的它们从行上面要走到同一行需要2*大行的差异,考虑列,因为每次向下走时,可以选择列数不变或者加一,比如第r大行,k列可以走到r+1行,k列或者k+1列,且这两种方式都是消耗同样的步骤。

     5、所以如果第二个点(这里默认第一个点小于第二个点)的列数减去第一个点的列数小于它们行数只差且不为负,那么列之间的差异可以不予考虑。否则,需要花2步/每列走过去。

   6、如果同属相同类型的小行,则上面算出的就是结果,否则,还要因为小行的不同做适当的+1或-1操作(根据初始小行k2-k1)

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int inf=1000000000;
 6 int po[100000],pn;
 7 void getpos(int n,int &r,int &c,int &k)
 8 {
 9     int ll=0,rr=pn-1,mid;
10     while(ll<=rr)
11     {
12         mid=(ll+rr)>>1;
13         if(po[mid]<n)
14         {
15             r=mid;
16             ll=mid+1;
17         }
18         else
19         {
20             rr=mid-1;
21         }
22     }
23     c=n-po[r];
24     if(c&1)
25     {
26         r++;
27         c=(c+1)>>1;
28         k=1;
29     }
30     else
31     {
32         c=c>>1;
33         k=2;
34     }
35 }
36 int main()
37 {
38     int i;
39     for(i=0; i*i<inf; i++)
40         po[i]=i*i;
41     pn=i;
42     int a,b,ra,ca,ka,rb,cb,kb;
43     while(scanf("%d%d",&a,&b)!=EOF)
44     {
45         if(a>b)
46             swap(a,b);
47         getpos(a,ra,ca,ka);
48         getpos(b,rb,cb,kb);
49         int ans=kb-ka;
50         if(ra!=rb)
51             ans+=(rb-ra)*2;
52         if(cb<ca)
53             ans+=(ca-cb)*2;
54         else if(cb>ca-ra+rb)
55             ans+=(cb-ca+ra-rb)*2;
56         printf("%d\n",ans);
57     }
58     return 0;
59 }