【BZOJ】3505: [Cqoi2014]数三角形

题意

\(n * m(1 \le n, m \le 1000)\)的网格,求顶点在格点上三角形的个数。

分析

假设\(n \le m\)
\(ans = \binom{(n+1) * (m+1)}{3} - L\),其中\(L\)表示三点共线的方案数。
所以

$$ \begin{align} L & = \frac{1}{2} \sum_{dx=0}^{n} \sum_{dy=0}^{m} \sum_{fx=0}^{n} \sum_{fy=0}^{m} (gcd(|dx-fx|, |dy-fy|)-1) \\ & = 2 \sum_{x=0}^{n} \sum_{y=0}^{m} \sum_{i=1}^{x} \sum_{j=1}^{y} (gcd(i, j)-1) + (m+1) \binom{n+1}{3} + (n+1) \binom{m+1}{3} \\ & = 2 f(n, m) + (m+1) \binom{n+1}{3} + (n+1) \binom{m+1}{3} \\ \\ f(n, m) & = \sum_{x=0}^{n} \sum_{y=0}^{m} \sum_{i=0}^{x} \sum_{j=0}^{y} (gcd(i, j)-1) \\ & = \sum_{x=0}^{n} \sum_{y=0}^{m} \left( \sum_{i=0}^{x} \sum_{j=0}^{y} gcd(i, j) - x * y \right) \\ & = \sum_{x=0}^{n} \sum_{y=0}^{m} (g(x, y) - x * y) \\ \\ g(n, m) & = \sum_{i=0}^{n} \sum_{j=0}^{m} gcd(i, j) \\ & = g(n, m-1) + \sum_{i=0}^{n} gcd(i, m) \\ & = g(n, m-1) + h(n, m) \\ \\ h(n, m) & = \sum_{i=0}^{n} gcd(i, m) \\ & = h(n-1, m) + gcd(n, m) \\ \end{align} $$

用这个\(O(n^2 log n)\)的是可以过的,所以就不用推下去了。

题解

分析已经推出一个\(O(n^2 log n)\)的做法,更优做法请自己推~

#include <bits/stdc++.h>
using namespace std;
const int N=1005;
typedef long long ll;
int gcd(int a, int b) {
    return b?gcd(b, a%b):a;
}
int n, m;
ll G[N][N], f[N][N];
int main() {
    scanf("%d%d", &n, &m);
    ll ans=0, t=(n+1)*(m+1);
    ans=(t*(t-1)*(t-2)-(ll)(n+1)*n*(n-1)*(m+1)-(ll)(m+1)*m*(m-1)*(n+1))/6;
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=m; ++j) {
            f[i][j]=f[i-1][j]+gcd(i, j);
            G[i][j]=G[i][j-1]+f[i][j];
        }
    }
    t=0;
    for(int x=0; x<=n; ++x) {
        for(int y=0; y<=m; ++y) {
            t+=G[x][y]-x*y;
        }
    }
    printf("%lld\n", ans-t*2);
    return 0;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4986021.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值