2.梅花桩
(blossom.pas/c/cpp)
【问题描述】
小x在练习一门轻功,这门轻功是在梅花桩上跳来跳去,这门轻功是严格按照直线从一个梅花桩直接跳到另外一个梅花桩上。因为小x有恐高症,所以除了开始和结束的两个梅花桩,这条直线上不能有其他梅花桩,否则小x会真气中断,直接掉下来。
小x的梅花桩有W+1行,H+1列,每个梅花桩之间距离都是1米,严格按照上下左右排列,小x的轻功最少能跳L1米,最多能跳L2米。
作为一位爱思考的数学青年,小x想到了一个问题:有多少对梅花桩对小x来说是安全的,或者说有多少对梅花桩能保证小x练习这门轻功。
例如如下的地图:
W = 2 H = 1
**
**
**
而小x跳跃的长度为2和3之间。
这个梅花桩共有 (2+1) * (1+1) = 6个点以及有15 种配对方法
(0,0)-(0,1) (0,0)-(2,1) (0,1)-(2,1) (1,1)-(2,0)
(0,0)-(1,0) (0,1)-(1,0) (1,0)-(1,1) (1,1)-(2,1)
(0,0)-(1,1) (0,1)-(1,1) (1,0)-(2,0) (2,0)-(2,1)
(0,0)-(2,0) (0,1)-(2,0) (1,0)-(2,1)
在这之中,只有四种是可以满足小x跳跃长度的
始位 末位 长度 始位 末位 长度
(0,0)-(2,0) 2.00 (0,1)-(2,0) 2.24
(0,0)-(2,1) 2.24 (0,1)-(2,1) 2.00
但在这四种之中,(0,0)-(2,0)和(0,1)-(2,1)都不符合直线上没有其他梅花桩的要求,所以这个样例中只有2种结果。
【输入】
一行,4个整数W, H, L1, 和 L2
【输出】
一行。可能的方案数。
【输入输出样例】
blossom.in |
blossom.out |
2 1 2 3 |
2 |
【数据范围】
50%数据 0<w,h,L1,L2<=100
100% 数据 1 <= L1 <= L2 <= 1,500 1 <= W <= 1,000; 1 <= H <= 1,000
思路:
50%的分很好拿(四重循环)。
但是如何拿满分?(这个问题好)HOW
首先,如果L1<=1时,所有相邻为一的点都满足要求。
if(l1<=1) ans=ans+w*(h+1)+h*(w+1);
显然,当w=3,h=3时有(w+1)*h+h*(w+1);
然后,就枚举(x,y)到(0,0)的距离。如果小于L2,大于L1则算出有多少那样的矩形*2.
ans+=(w+1-x)*(h+1-y)
cpp:
1 #include<iostream> 2 #include<string> 3 #include<ctime> 4 #include<cstdio> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 #include<algorithm> 9 #include<queue> 10 #include<iomanip> 11 using namespace std; 12 const int maxn=5000001; 13 int w,h,l1,l2; 14 long long ans=0; 15 int gcd(int a,int b) 16 { 17 return b==0?a:gcd(b,a%b); 18 } 19 20 int main() 21 { 22 freopen("blossom.in","r",stdin); 23 freopen("blossom.out","w",stdout); 24 ios::sync_with_stdio(false); 25 cin>>w>>h>>l1>>l2; 26 if(l1<=1) 27 ans=ans+w*(h+1)+h*(w+1); 28 for(int i=1;i<=w;i++) 29 { 30 for(int j=1;j<=h;j++) 31 { 32 int x=i*i+j*j; 33 if(x>=l1*l1&&x<=l2*l2) 34 { 35 x=gcd(i,j); 36 if(x==1) 37 { 38 ans=ans+(w-i+1)*(h-j+1)*2; 39 } 40 } 41 } 42 } 43 cout<<ans<<endl; 44 return 0; 45 }