首页 > 学院 > 开发设计 > 正文

Kickstart2017 Round A - A.Square Counting(Math)

2019-11-06 06:19:50
字体:
来源:转载
供稿:网友

¥## 题目链接 https://code.google.com/codejam/contest/8284486/dashboard

题意

给一个m⋅n的格点图,求这个格点图中正方形的数目。

思路

包括正正方形和斜正方形。

正正方形数目

我们用f(i)表示边长为i的正方形数目。

明显可知f(1)=mn,我们推一下f(2),f(3)...

设如下格点图的长为m,宽为n(设m≥n): 这里写图片描述 首先我们选定左上角的边长为2的正方形。

我们水平向右平移,每次平移一个单位,可以平移m−2次,会产生m−12⋅2的正方形。我们将其向下平移,每次平移一个单位,可以平移n−2次,会产生n−12⋅2的正方形。

于是我们可知f(2)=(m−1)(n−1)

同理可以推得f(3)=(m−2)(n−2), f(4)=(m−3)(n−3), f(n)=(m−(n−1))(n−(n−1))

所以我们正正方形的数目:

ans1=f(1)+f(2)+...+f(n)

=∑i=1n(m−(i−1))(n−(i−1))

=∑i=0n−1(m−i)(n−i)

​ = n(n+1)(3m−n+1)6

斜正方形数目

首先,假设我们已经有一个i⋅i的正正方形了,那么正正方形中的最大斜正方形(表示其不能再增大)有多少个呢?我们设g(i)为边长为i的正正方形数目包含的最大斜正方形数目。

假设i=2g(i)=1 这里写图片描述

假设i=3g(i)=2 这里写图片描述

其实观察可知:在边长为i⋅i的正正方形里面,最大斜正方形的数目g(i)=i−1(选定一条边,除去最两边的2个点,其他点都有最大斜正方形)。

那么,我们每个边长为i⋅i的正正方形里面都有g(i)个斜正方形,我们边长为i的正正方形有f(i)个,那么所有的斜正方形数目为:

ans2=f(1)g(1)+f(2)g(2)+...+f(n)g(n)

=∑i=1nf(i)g(i)

=∑i=0n−1f(i)g(i)

=∑i=0n−1(m−i)(n−i)(i−1)

=n(2m−n)(n+1)(n−1)12

所以我们最后的结果为:n(n+1)(3m−n+1)6+n(2m−n)(n+1)(n−1)12

代码

#include <bits/stdc++.h>using namespace std;inline int in() {int x; scanf("%d", &x); return x;}#define PR(x) {cout << #x << ' ' << x << endl;}#define LL long longconst LL mod = 1e9 + 7;LL power(LL a, LL n) { LL res = 1; while (n) { if (n & 1) res *= a, res %= mod; a *= a; a %= mod; n >>= 1; } return res % mod;}LL DIV(LL a, LL b) { LL t = power(b, mod - 2); return a * t % mod;}LL mul(LL a, LL b) { return a * b % mod;}inline LL add(LL a, LL b) { return a + b < mod ? a + b : a + b - mod;}int main() { int T = in(), kase = 1; while (T--) { LL m, n; cin >> m >> n; m--, n--; if (m < n) swap(m, n); LL v1 = mul(n, n + 1); LL v2 = (3 * m - n + 1) % mod; LL res1 = mul(v1, v2); res1 = DIV(res1, 6); LL v3 = (2 * m - n) % mod; v3 = mul(n, v3); LL v4 = mul(n + 1, n - 1); LL res2 = mul(v3, v4); res2 = DIV(res2, 12); LL ans = add(res1, res2); cout << "Case #" << kase++ << ": " << ans << endl; } return 0;}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表