题意:给出一个特殊构造的三角形,具体看原题的图,问从第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 }