bzoj 3505 //3505: [Cqoi2014]数三角形 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=3505
更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录
//3505: [Cqoi2014]数三角形
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=3505
//刚开始读题,就发现,没图,网络中搜索了一圈,也没找到图,那就耐心读题,拿出纸笔画画
//题意在没有图的情况下弄懂了.
//数据范围1<=m,n<=1000,递归是没则了,O(n^2)的算法
//用到什么数学,2*2 76的模拟还是比较困难的.
//思路源于此文https://www.luogu.org/problemnew/solution/P3166 作者: BillYang 更新时间: 2017-07-29 21:02 代码注释
//任选3个点-共线的3个点=三角形个数
//共线3个点=水平共线+竖直共线+倾斜共线,难点在于倾斜共线的计算
(m-i)*(n-j)*(gcd(i,j)+1-2)*2;//倾斜共线 理解如下,以2*2为例,自加1,m=3,n=3
i=1,j=1
(m-i)*(n-j)=(3-1)*(3-1)=4 4指边长为1*1的矩形有4个;
gcd(i,j)+1-2=gcd(1,1)+1-2=0,是指(0,0)-(1,1)这个线段中间有几个点(首尾两个点不算)
*2原因是下图中,1*1的对角线有2个,实线,虚线各1个。
i=1,j=2
(m-i)*(n-j)=(3-1)*(3-2)=2 2指边长为1*2的矩形有2个;
gcd(i,j)+1-2=gcd(1,2)+1-2=0,是指(0,0)-(1,2)这个线段中间有几个点(首尾两个点不算)
*2原因是下图中,1*2的对角线有2个,实线,虚线各1个。
i=2,j=1
(m-i)*(n-j)=(3-2)*(3-1)=2 2指边长为2*1的矩形有2个;
gcd(i,j)+1-2=gcd(2,1)+1-2=0,是指(0,0)-(2,1)这个线段中间有几个点(首尾两个点不算)
*2原因是下图中,2*1的对角线有2个,实线,虚线各1个。
i=2,j=2
(m-i)*(n-j)=(3-2)*(3-2)=1 1指边长为2*2的矩形有1个;
gcd(i,j)+1-2=gcd(2,2)+1-2=1,是指(0,0)-(2,2)这个线段中间有几个点(首尾两个点不算)
*2原因是下图中,2*2的对角线有2个,实线,虚线各1个。
至于倾斜直线算法,为什么不会有遗漏,为什么不会有重复,请读者自行画图,多画画,应该能理解。2019-8-30 16:04
//该题数量庞大,采用long long
//样例通过,提交AC.2019-8-30 14:49
#include <stdio.h>
#define LL long long
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int i,j;
LL ans,m,n;
scanf("%lld%lld",&m,&n),m++,n++;
ans=m*n*(m*n-1)*(m*n-2)/(3*2*1);//任选3个点数 C(n,3) 全集
if(n>=3)ans-=n*(n-1)*(n-2)/(3*2*1)*m;//水平共线
if(m>=3)ans-=m*(m-1)*(m-2)/(3*2*1)*n;//竖直共线
for(i=1;i<m;i++)//i边长
for(j=1;j<n;j++)//j边长
if(gcd(i,j)+1-2>0)ans-=(m-i)*(n-j)*(gcd(i,j)+1-2)*2;//倾斜共线
printf("%lld\n",ans);
}