藏妹子之处(excel)

试题描述
今天CZY又找到了三个妹子,有着收藏爱好的他想要找三个地方将妹子们藏起来,将一片空地抽象成一个R行C列的表格,CZY要选出3个单元格。但要满足如下的两个条件:
(1)任意两个单元格都不在同一行。
(2)任意两个单元格都不在同一列。
选取格子存在一个花费,而这个花费是三个格子两两之间曼哈顿距离的和(如(x1,y1)和(x,y2)的曼哈顿距离为|x1-x2|+|y1-y2|)。狗狗想知道的是,花费在minT到maxT之间的方案数有多少。
答案模1000000007。所谓的两种不同方案是指:只要它选中的单元格有一个不同,就认为是不同的方案。
输入
一行,4个整数,R、C、minT、maxT。3≤R,C≤4000, 1≤minT≤maxT≤20000。
对于30%的数据,  3 ≤ R, C ≤ 70。
输出
一个整数,表示不同的选择方案数量模1000000007后的结果。
输入示例
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;
}