P3166[CQOI2014]数三角形

P3166[CQOI2014]数三角形

0x01 题意

给定一个\(N\times M\)的网格,请计算三点都在格点上的三角形共有多少个。注意三角形的三点不能共线。

0x02 解

简简单单写公式

\[ans=C_{(m+1)(n+1)}^3-(n+1)C_{m+1}^3-(m+1)C_{n+1}^3-斜线共线情况 \]

怎么处理斜线共线情况?

  1. \(O(n^2)\) 能过

枚举两点之间横坐标相差\(i\),纵坐标相差\(j\)

方案数为

\[\sum_{i=1}^n \sum_{j=1}^m (n-i+1)(m-j+1)(gcd(i,j)-1) \]

其中\(gcd(i,j)-1\)是斜线穿过点的个数(不包括顶点)

  1. \(O(n)\) 神仙做法

这里

0x03 代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,m;
int ans=0,res=0;

int gcd(int a,int b){
	return (b==0)?a:gcd(b,a%b);
}

signed main(){
	cin>>n>>m;
	
	ans+=(n*m+n+m+1)*(n*m+n+m)*(n*m+n+m-1)/6;
	ans-=(m+1)*(n+1)*n*(n-1)/6;
	ans-=(n+1)*(m+1)*m*(m-1)/6;
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			res+=(n-i+1)*(m-j+1)*(gcd(i,j)-1);
	
	cout<<ans-res*2;
	
	return 0;
}
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1010;

int n,m;
int ans=0,res=0;

bool notp[N];
int cnt=0,phi[N],pri[N];
void getphi(int n){
	cnt=0;
	notp[1]=1,phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!notp[i]) pri[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&pri[j]*i<=n;j++){
			notp[pri[j]*i]=1;
			if(i%pri[j]==0){phi[pri[j]*i]=phi[i]*pri[j];break;}
			else phi[pri[j]*i]=phi[i]*(pri[j]-1);
		}
	}
}

signed main(){
	cin>>n>>m;
	
	ans+=(n*m+n+m+1)*(n*m+n+m)*(n*m+n+m-1)/6;
	ans-=(m+1)*(n+1)*n*(n-1)/6;
	ans-=(n+1)*(m+1)*m*(m-1)/6;
	
	if(n>m) swap(n,m);
	getphi(n);
	for(int d=2;d<=n;d++)
		res+=phi[d]*(n-d+n%d+2)*(n/d)*(m-d+m%d+2)*(m/d)/2;
	
	cout<<ans-res;
	
	return 0;
}
posted @ 2021-02-27 20:41  wsy_jim  阅读(69)  评论(0编辑  收藏  举报