Problem:
|x| <= a,|y| <= b,在这个网格中除了原点都有树,同一条直线会互相遮挡,问站在原点能看到多少棵树?
Solution:
不难发现我们是在定范围内找到有多少个互素的数对,但两个变量的范围有所不同,我们想到若gcd(x,i)==1,那么gcd(x+i,x)==gcd(x,i)==1,也就是说对于一个固定的x,i从1~x和i从2x+1~3x的取值都是phi(x),而多出来的那部分直接枚举就好了,所以我们遍历每一个x,求得他们每一个解的和就是总共的树的棵树。
note:
1. 要充分理解最大公约数的相关定理。
2. 根据数据量试图进行相应的枚举找思路。
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<string>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<ctime>
#include<vector>
#include<fstream>
#include<list>
using namespace std;
#define ms(s) memset(s,0,sizeof(s))
typedef unsigned long long ULL;
typedef long long LL;
const int INF = 0x3fffffff;
const int maxn = 2000;
int phi[maxn+5];
void phi_table(){
memset(phi,0,sizeof(phi));
phi[1] = 1;
for(int i = 2; i <= maxn; i++){
if(phi[i] == 0){
for(int j = i; j <= maxn; j += i){
if(phi[j] == 0)
phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
}
}
int gcd(int a, int b){
a = abs(a); b = abs(b);
while(b != 0){
int t = a%b;
a = b;
b = t;
}
return a;
}
int main(){
// freopen("F:\\input.txt","r",stdin);
// freopen("F:\\output.txt","w",stdout);
// ios::sync_with_stdio(false);
phi_table();
LL a,b;
LL ans;
LL tot;
double ans2;
while((~scanf("%lld%lld",&a,&b)) && a){
ans = 0LL;
if(a > b)
swap(a,b);
for(LL i = 1; i <= a; ++i){
ans += (b/i)*phi[i];
for(LL j = i*(b/i)+1; j <= b; ++j){
if(gcd(i,j)==1){
ans++;
}
}
}
ans *= 4LL;
ans += 4LL;
tot = a*b*4LL+2LL*a+2LL*b;
ans2 = (double)ans/(double)tot;
printf("%.7f\n",ans2);
}
return 0;
}