P3166[CQOI2014]数三角形

P3166[CQOI2014]数三角形

0x01 题意

给定一个(N imes 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;
}
原文地址:https://www.cnblogs.com/wsyunine/p/14457121.html