Loading

AT_agc018_e [AGC018E] Sightseeing Plan

计数好题。

要做出这道题首先考虑更简单的问题,只规定起点矩阵和终点矩阵怎么做?有点困难,没关系,我们可以先考虑求一个点到一个矩阵的路径数,不妨设起点为 \((0,0)\),矩阵显然是可以差分的,这样我们就只需要求 \(f(x,y)=\sum_{i=0}^x\sum_{j=0}^y\binom{i+j}{i}\) 了。

有两种方法求,一种是考虑一个递推关系,这种东西一看就是有递推关系的对吧?那么我们考虑令 \(g(x,y)\) 为到它的路径数,那么,\(g(x,y)=\sum_{j=0}^yg(x-1,j)\)。这是显然的,它有什么用呢?它可以代替前面一整列的贡献。那么对于 \(f(x,y)\),我们发现 \(g(x+1,y+1)\) 恰好可以将贡献一一对应的算出来,真是神奇!

还有一种更有一般性的方法,就是直接推组合数。考虑式子的形式,我们不妨将 \(\binom{i+j}{i}\) 变为 \(\binom {i+j} j\),于是

\[\begin{align}f(x,y)&=\sum_{i=0}^x\sum_{j=0}^y\binom{i+j+1}{j+1}-\binom{i+j}{j+1}\\&=\sum_{j=0}^{y+1}\binom{x+j}{x}\\&=\sum_{j=0}^{y+1}\binom{x+j+1}{j+1}-\binom{x+j}{j+1}\\&=\binom{x+y+2}{x+1}\\&=g(x+1,y+1) \end{align} \]

主要利用了拆组合数抵消邻项的思想。

那么我们会了点到矩形之后,发现我们已经可以枚举中间矩形的轮廓,但是我们发现不同的 \(P\) 会使得相同的路径多算,那么一条路径的权值相当于经过的点数,然而我们发现经过的点数等于进出的两个点的曼哈顿距离,这样就可以拆开算了。

代码:

#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i (l); i <= r; ++ i)
#define rrp(i, l, r) for (int i (r); i >= l; -- i)
#define eb emplace_back
using namespace std;
#define pii pair <int, int>
#define inf 1000000000
constexpr int N = 2e6 + 5, M = 1e5, P = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + (ch ^ 48);
    ch = getchar ();
  }
  return x * f;
}
int qpow (int x, int y, int p = P) {
  int ret (1);
  for (; y; y >>= 1, x = x * x % p) if (y & 1) ret = ret * x % p;
  return ret;
}
int x[7], y[7];
int fac[N], ifac[N];
int C (int n, int m) {
  if (m > n) return 0;
  return fac[n] * ifac[m] % P * ifac[n - m] % P;
}
int calc (int X1, int Y1, int X2, int Y2) {
  return C (X2 - X1 + Y2 - Y1, X2 - X1);
}
int pre (int X, int Y) {
  return (calc (x[1] - 1, y[1] - 1, X, Y)
     - calc (x[2], y[1] - 1, X, Y)
     - calc (x[1] - 1, y[2], X, Y)
     + calc (x[2], y[2], X, Y) + P + P) % P;
}
int suf (int X, int Y) {
  return (calc (X, Y, x[6] + 1, y[6] + 1)
     - calc (X, Y, x[5], y[6] + 1)
     - calc (X, Y, x[6] + 1, y[5])
     + calc (X, Y, x[5], y[5]) + P + P) % P;
}
int32_t main () {
  // freopen ("1.in", "r", stdin);
  // freopen ("1.out", "w", stdout);
  fac[0] = 1;
  rep (i, 1, N - 1) fac[i] = fac[i - 1] * i % P;
  ifac[N - 1] = qpow (fac[N - 1], P - 2);
  rrp (i, 1, N - 1) ifac[i - 1] = ifac[i] * i % P;
  rep (i, 1, 6) x[i] = rd ();
  rep (i, 1, 6) y[i] = rd ();
  int ret (0);
  rep (i, x[3], x[4]) {
    ret += P - pre (i, y[3] - 1) * suf (i, y[3]) % P * (i + y[3]) % P;

    ret += pre (i, y[4]) * suf (i, y[4] + 1) % P * (i + y[4] + 1);

    ret %= P;
    // cout<<ret<<" "<<suf (i, y[3])<<" "<<pre (i, y[4]) * suf (i, y[4])<<endl;
  }
  rep (i, y[3], y[4]) {
    ret += P - pre (x[3] - 1, i) * suf (x[3], i) % P * (x[3] + i) % P;
    ret += pre (x[4], i) * suf (x[4] + 1, i) % P * (x[4] + i + 1);

    ret %= P;
  }
  cout << ret;
}
posted @ 2025-03-17 22:12  lalaouye  阅读(9)  评论(0)    收藏  举报