链接:http://acm.hdu.edu.cn/showproblem.php?pid=2073
意外之喜 还挺不错的一道题目
仔细观察不难发现 其实整个路线只有这两种线(绿色跟红色)
并且在移动过程中[x,y]的改变(红线部分)总是遵循这两种规律[x+1,y-1]或者[x-1,y+1],设x+y=z
在同一条红线中z的值是不变的
既然如此 我们不如直接用x+y来计算红线部分的总值,忽略x与y的具体数值
我们定义一个数组p1[z]来保存红线的前缀和
计算公式也很容易看出来p1[0] = 0; p[i] = p[i-1]+i*g; // double g = sqrt(2); 很容易看出来 第i条红线恰好有条长度为sqrt(2)的线段
那么现在红线部分就搞定了
接下来定义一个数组p2[z]来保存绿线的前缀和
同样用开平方根的方式计算第x跟绿线的长度 第x根绿线的长度为sqrt(x^2+(x+1)^2);
p2[0] = 0; p2[i] = p[i-1]+sqrt(i^2+(i-1)^2);
此时我们只需要判断出给出的坐标点位于哪条红线上,将这条红线之前的前缀和加到sum上
再根据x的值判断这之前有多少条绿线 再将这些绿线的前缀和加到sum上
现在就只剩下最后一个问题了 即加上最后一段的距离
比如计算[3,1](距离[0,0])的长度
加上前(3+1)-1条红线 再加上前(3+1)条绿线 再加上最后一段的距离
对于[3,1],最后一段的距离是[0,4]->[1,3]->[2,2]->[3,1];(发现恰好为三个g的距离)
再尝试观察几个其他的点 发现最后一段距离恰好为x个g的距离
那么公式就出来了 sum[x,y]=p1[x+y-1]+p2[x+y]+x*g;
那么我们只需要计算一次[x1,y1]的sum,再计算一次[x2,y2]的sum进行相减取绝对值
最后的结果便出来了
1 #include <bits/stdc++.h> 2 using namespace std; 3 double p1[210],p2[210]; 4 double g = sqrt(2); 5 int main() 6 { 7 int i,j,x1,y1,x2,y2; 8 double num1,num2; 9 p1[0] = 0.0; 10 for(int i = 1;i <= 205;i++) 11 p1[i] = p1[i-1]+(i)*g; 12 p2[0] = 0; 13 for(int i = 1;i <= 205;i++) 14 p2[i] = sqrt(i*i+(i-1)*(i-1))+p2[i-1]; 15 int n; 16 cin >> n; 17 while(n--) 18 { 19 scanf("%d %d %d %d",&x1,&y1,&x2,&y2); 20 num1 = p1[x1+y1-1]+x1*g+p2[x1+y1]; 21 num2 = p1[x2+y2-1]+x2*g+p2[x2+y2]; 22 printf("%.3lf\n",fabs(num1-num2)); 23 } 24 return 0; 25 }
原文地址:https://www.cnblogs.com/duny31030/p/8974216.html