题目描述:
在本题中,格点是指横纵坐标皆为整数的点。
为了圈养他的牛,农夫约翰建造了一个三角形的电网。他从原点(0,0)牵出一根通电的电线,连接格点(n,m)(0<=n<32000,0 < m<32000),再连接格点(p,0)(p>0),最后回到原点。
牛可以在不碰到电网的情况下被放到电网内部的每一个格点上(十分苗条的牛)。如果一个格点碰到了电网,牛绝对不可以被放到该格点之上。那么有多少头牛可以被放到农夫约翰的电网中去呢?
INPUT FORMAT:
输入文件只有一行,包含三个用空格隔开的整数:n,m和p。
OUTPUT FORMAT:
输出文件只有一行,包含一个整数,代表能被指定的电网包含的牛的数目。
SAMPLE INPUT
7 5 10
SAMPLE OUTPUT
20
题目思路:
我用的就是很容易想到的枚举从0到max(n,p)每个部分的格点数,根据n,p的大小关系分开处理即可。
在USACO看到了皮克定理:
其面积S和内部格点数目a、边上格点数目b的关系:S = a + b/2 - 1。
根据三角形面积公式求出S,如果知道了b,那么三角形内部格点数目a也就求出来了。 可以证明,一条直线((0,0),(n,m))上的格点数等于n与m的最大公约数+1, 即b=gcd(n,m)+1. gcd(n,m)为n与m的最大公约数。 代入皮克公式,即可求出a的值。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#define INF 99999999
using namespace std;
FILE *fin,*fout;
int n,m,p,ans=0;
int main(){
fin = fopen ("fence9.in", "r");
fout = fopen ("fence9.out", "w");
fscanf(fin,"%d%d%d",&n,&m,&p);
if(p>=n){
for(int i=1;i<n;i++){
ans+=m*i/n;
if(m*i%n==0)ans--;
}
for(int i=n;i<p;i++){
if(i==0)continue;
ans+=m*(p-i)/(p-n);
if(m*(p-i)%(p-n)==0)ans--;
}
}else{
for(int i=1;i<n;i++){
ans+=m*i/n;
if(m*i%n==0)ans--;
if(i>=p)
ans-=m*(i-p)/(n-p);
}
}
fprintf(fout,"%d\n",ans);
exit(0);
}