藏妹子之处(excel)
(1)任意两个单元格都不在同一行。
(2)任意两个单元格都不在同一列。
选取格子存在一个花费,而这个花费是三个格子两两之间曼哈顿距离的和(如(x1,y1)和(x,y2)的曼哈顿距离为|x1-x2|+|y1-y2|)。狗狗想知道的是,花费在minT到maxT之间的方案数有多少。
答案模1000000007。所谓的两种不同方案是指:只要它选中的单元格有一个不同,就认为是不同的方案。
对于30%的数据, 3 ≤ R, C ≤ 70。
6 19 4 18776
输出示例
116280
不难发现,不共线的三点的曼哈顿距离和等于一个矩形的周长,而共线的三点俩俩曼哈顿距离和等于最远两个点曼哈顿距离×2.
注意到题目说两点不能在同一行同一列,所以我们可以平面上这三个点分别投影到x轴和y轴上。投影后x轴、y轴上各有三点。
相反地,在x轴、y轴上分别找3点,也可以将它还原成平面上3个点的状态,所以可以分别算出确定x轴、y轴上三点的方案数Ax和Ay
不难得出当最远两点距离为i,总共有n个位置时Axi = (n - i) * (i - 1).
Ayi的计算方法同理。
x轴、y轴上的点找好后,剩下的问题就是还原成平面上3个点的状态了,设x轴上三个点为X1, X2, X3,y轴上三点Y1, Y2, Y3。
那么当X1, X2, X3顺序确定后,Y1, Y2, Y3的每一个排列都能还原成一个状态,所以方案数为6Axi · Ayj
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 4010 #define MOD 1000000007 #define LL long long int n, m, mint, maxt; LL an[maxn], am[maxn], ans; void solve() { for(int i = 1; i <= n; i++) for(int j = 1; j <= m && ((i + j) << 1) <= maxt; j++) if(mint <= ((i + j) << 1)) (ans += ((an[i] * (am[j] * 6 % MOD)) % MOD)) %= MOD; return ; } int main() { n = read(); m = read(); mint = read(); maxt = read(); for(int i = 1; i <= n; i++) an[i] = (LL)(n - i) * (i - 1) % MOD; for(int i = 1; i <= m; i++) am[i] = (LL)(m - i) * (i - 1) % MOD; solve(); printf("%lld\n", ans); return 0; }