codechef - TBGRAPH - 题解

Graph on a Table

题意

有一张 $ n \times m $ 的网格图,每次可以从 $ (x_0, y_0) $ 跳到 $ (x_1, y_1) $ 当且仅当 $ x_0 < x_1 $ 且 $ y_0 < y_1 $ ,同时这两个点都要在同一个给出的矩形中,求最多可以经过多少个网格并求出方案数对 $ 10^9 + 7 $ 取模。

做法

由于要求的是最长路经,所以对于路径相邻的两个位置 $ (x_i, y_i) $ 和 $ (x_{i + 1}, y_{i + 1}) $ 满足 $ x_i + 1 = x_{i + 1} $ 或 $ y_i + 1 = y_{i + 1} $ 。
考虑DP,预处理出每个点可以从那些地方转移( $ Left[i][j] $ 和 $ Up[i][j] $ 分别维护这个点可以转移的最左和最上方的位置 )。
然后单调队列优化DP即可。

#include <bits/stdc++.h>
#define mp make_pair
#define fst first
#define snd second
#define rep(i, a, b) for(int i = (a), i##ed = (b); i <= i##ed; i++)
#define per(i, a, b) for(int i = (a), i##ed = (b); i >= i##ed; i--)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2010, M = 500010;

inline void file() {
    freopen("roche.in", "r", stdin);
    freopen("roche.out", "w", stdout);
}
inline int Max(int x, int y) { return x > y ? x : y; }
inline int Min(int x, int y) { return x < y ? x : y; }
void gi(int &x) {
    x= 0; register char c = getchar();
    for(; c < '0' || c > '9'; c = getchar());
    for(; c >= '0' && c <= '9';)
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
}

int T, n, m, q;
struct P {
    int x, y, xx, yy;
    inline bool operator<(const P &yy)const { return x < yy.x; }
}; P a[M];
int up[N][N], lt[N][N];
struct Node {
    int len, s; Node(int X = 0, int Y = 0) : len(X), s(Y) {}
    inline bool operator<(const Node &yy)const { return len < yy.len; }
}; Node ans, f[N][N];
struct Queue {
    Node a[N]; int f, e, s[N], id[N];
    void init(int x) { f = 1, e = 0; rep(i, 1, x) s[i] = 0; }
    void push(int x, Node w) {
        for(; f <= e && a[e] < w;)
            s[a[e].len] = (s[a[e].len] - a[e].s + mod) % mod, --e;
        s[w.len] = (s[w.len] + w.s) % mod, a[++e] = w, id[e] = x;
    }
    Node ask(int x) {
        for(; f <= e && id[f] < x;)
            s[a[f].len] = (s[a[f].len] - a[f].s + mod) % mod, ++f;
        return Node(a[f].len + 1, s[a[f].len]);
    }
}; Queue Up[N], Lt[N];

inline Node operator+(Node x, Node y) {
    if(x.len ^ y.len) return x.len > y.len ? x : y;
    return Node(x.len, (x.s + y.s) % mod);
}
void get_up_lt() {
    rep(i, 1, n) rep(j, 1, m) up[i][j] = lt[i][j] = 0x3f3f3f3f;
    rep(i, 1, q) {
        rep(j, a[i].x + 1, a[i].xx)
            lt[j][a[i].yy] = Min(a[i].y, lt[j][a[i].yy]);
        rep(j, a[i].y + 1, a[i].yy)
            up[a[i].xx][j] = Min(a[i].x, up[a[i].xx][j]);
    }
    per(i, n, 1) per(j, m, 1) {
            if(j < m) lt[i][j] = Min(lt[i][j + 1], lt[i][j]);
            if(i < n) up[i][j] = Min(up[i + 1][j], up[i][j]);
            if(lt[i][j] >= j) lt[i][j] = 0x3f3f3f3f;
            if(up[i][j] >= i) up[i][j] = 0x3f3f3f3f;
        }
}
void solve() {
    gi(n), gi(m), gi(q);
    rep(i, 1, q) gi(a[i].x), gi(a[i].y), gi(a[i].xx), gi(a[i].yy);
    get_up_lt();
    rep(i, 1, n) Lt[i].init(m); rep(i, 1, m) Up[i].init(n);
    rep(i, 1, n) rep(j, 1, m) f[i][j] = Node(1, 1);
    rep(i, 1, n) rep(j, 1, m) {
        Lt[i].push(j, f[i][j]), Up[j].push(i, f[i][j]);
        if(lt[i + 1][j + 1] != 0x3f3f3f3f)
            f[i + 1][j + 1] = f[i + 1][j + 1] + Lt[i].ask(lt[i + 1][j + 1]);
        if(up[i + 1][j + 1] != 0x3f3f3f3f)
            f[i + 1][j + 1] = f[i + 1][j + 1] + Up[j].ask(up[i + 1][j + 1]);
        if(up[i + 1][j + 1] != 0x3f3f3f3f && lt[i + 1][j + 1] != 0x3f3f3f3f &&
            f[i][j].len + 1 == f[i + 1][j + 1].len)
            f[i + 1][j + 1].s = (f[i + 1][j + 1].s - f[i][j].s + mod) % mod;
    }
    ans = Node(0, 0);
    rep(i, 1, n) rep(j, 1, m) ans = ans + f[i][j];
    printf("%d %d\n", ans.len, ans.s);
}
int main() {
//  file();
    for(scanf("%d", &T); T; --T) solve();
    return 0;
}

转载于:https://www.cnblogs.com/daniel14311531/p/10507150.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值