P3166 [CQOI2014]数三角形(组合数学)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3166 [CQOI2014]数三角形(组合数学)相关的知识,希望对你有一定的参考价值。
P3166 [CQOI2014]数三角形(组合数学)
整点三角形个数。
正难则反,求出总方案和共线三角形方案数即可。
总方案: C ( ( n + 1 ) ( m + 1 ) , 3 ) C((n+1)(m+1),3) C((n+1)(m+1),3)
共线分三种情况:水平、垂直、倾斜。
水平: ( n + 1 ) C m + 1 3 (n+1)C_{m+1}^3 (n+1)Cm+13
同理垂直: ( m + 1 ) C n + 1 3 (m+1)C_{n+1}^3 (m+1)Cn+13
考虑倾斜如何求,因为正斜率和反斜率是对称的。
所以只需算出正的然后乘以2即可。
因为两条直角边唯一确定斜边。
所以可以枚举两直角边长度 i , j i,j i,j。
然后以两个端点作为三角形的两端点,在斜边上再找一个点的方案。
结论是: g c d ( i , j ) − 1 gcd(i,j)-1 gcd(i,j)−1。
考虑斜边直线: g = g c d ( i , j ) , i = u g , j = v g , y = u v x g=gcd(i,j),i=ug,j=vg,y=\\dfrac{u}{v}x g=gcd(i,j),i=ug,j=vg,y=vux。
则 v ∣ x v|x v∣x。
这样的 x x x的个数是: j v − 1 = g − 1 = g c d ( i , j ) − 1 \\dfrac{j}{v}-1=g-1=gcd(i,j)-1 vj−1=g−1=gcd(i,j)−1。
减1是不包括两端。
所以这一部分答案就是: ∑ i = 1 n ∑ j = 1 m ( n − i + 1 ) ( m − j + 1 ) ( g c d ( i , j ) − 1 ) \\sum\\limits_{i=1}^n\\sum\\limits_{j=1}^m(n-i+1)(m-j+1)(gcd(i,j)-1) i=1∑nj=1∑m(n−i+1)(m−j+1)(gcd(i,j)−1)
事实上还可以用欧拉反演进行化简。
下面参考某大佬。
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 1005;
int n, m, p[maxn], phi[maxn], tot;
bool mark[maxn];
long long ans;
long long C(long long x) { return x * (x-1) * (x-2) / 6; }
void sieve(int n) {
phi[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!mark[i]) p[++tot] = i, phi[i] = i - 1;
for(int j = 1; j <= tot and p[j]*i <= n; ++j) {
mark[p[j]*i] = true;
if(i % p[j]) phi[p[j]*i] = phi[i] * (p[j]-1);
else { phi[p[j]*i] = phi[i] * p[j]; break; }
}
}
}
int main() {
scanf("%d %d", &n, &m);
if(n > m) swap(n, m);
sieve(n);
for(int d = 2, x, y; d <= n; ++d)//记得 ans 要乘以 2,这里直接除以 2 就行了不用除以 4
ans += (long long)phi[d]*(n-d+n%d+2)*(n/d)*(m-d+m%d+2)*(m/d)/2;
ans = C((n+1)*(m+1)) - (m+1)*C(n+1) - (n+1)*C(m+1) - ans;
printf("%lld\\n", ans);
}
以上是关于P3166 [CQOI2014]数三角形(组合数学)的主要内容,如果未能解决你的问题,请参考以下文章