1. 程式人生 > 程式設計 >如何利用python檢測圖片是否包含二維碼

如何利用python檢測圖片是否包含二維碼

顯然直接計數是不好計的,只能從 \(dp\) 這個角度來下手。

首先用最原始最直接的方法,直接在 \(dp\) 的過程中滿足題目的要求。

既然問題給在一棵樹上,那麼必然和樹脫不了關係,因此我們應該從樹形 \(dp\) 的角度下手。

因為在樹形 \(dp\) 的過程中我們只能考慮父子邊的選擇情況,那麼對於一個點 \(u\),那些限制鏈頂在 \(u\) 子樹內的限制鏈顯然在其父親 \(fa\) 進行轉移時是考慮不到的,因此設計狀態的時候必然要使得這些鏈已經被滿足。

那麼再來考慮這些鏈底在 \(u\) 子樹內,鏈頂在 \(u\) 的祖先上的這些鏈。

不難發現只需要滿足的鏈是鏈頂深度最深的這條鏈,因為只要滿足了它其他的鏈也會被滿足。

所以我們在 \(dp\) 的時候只關注於當前伸出去的鏈中鏈頂最深的鏈,於是我們的 \(dp\) 狀態就呼之欲出了。

考慮令 \(dp_{i, j}\) 表示以 \(i\) 為根的子樹內,還沒有被滿足限制的鏈中鏈頂伸出去的鏈的最深的鏈頂深度為 \(j\) 時的方案,特別地 \(j = 0\) 時表示沒有伸上來的鏈。

那麼轉移的時候只要考慮 \(u \rightarrow v\) 這條父子邊選 \(0 / 1\) 即可。

\(1\) 時,\(v\) 伸上來的所有鏈都會被滿足,於是有轉移:

\[dp_{u, i} \times \sum\limits dp_{v, j} \rightarrow dp_{u, i} \]

\(0\) 時,只需要考慮當前這個最深的鏈頂是否來自於 \(v\) 即可。

不來自於 \(v\) :

\[dp_{u, i} \times \sum\limits_{j = 0} ^ i dp_{v, j} \rightarrow dp_{u, i} \]

來自於 \(v\)

\[dp_{v, i} \sum\limits_{j = 0} ^ i dp_{u, j} \rightarrow dp_{u, i} \]

需要注意深度相同時 \(dp_{u, i} \times dp_{v, i} \rightarrow dp_{u, i}\) 被計算了兩次,需要減去。

但這樣依然不能通過本題,怎麼辦呢?

可以發現,這個 \(dp\) 的狀態量就驚人地達到了 \(O(n ^ 2)\),因此我們必須要從狀態這裡下手。

這時候我們引入一個叫做整體 \(dp\) 的技巧,其適用範圍往往是存在一個維度上初始值並不多的情況。

其做法就是將這一個需要優化的維度放到動態開點線段樹上,然後可以通過主席樹或線段樹合併一類技巧來優化這個 \(dp\) 的流程。

那麼在本題當中,我們可以將第二維放到動態開點線段樹上。

那麼對於第一條轉移,相當於是給 \(u\) 這個線段樹上每個位置乘上 \(v\) 中所有數之和,不難發現這可以直接線上段樹上完成。

對於第二條轉移,相當於是對於 \(u\) 所線上段樹上每個非 \(0\) 的點乘上 \(v\) 所線上段樹上 \(u\) 左側所有位置之和,不難發現這個操作是可以線上段樹合併的時候同時完成的,只需要遞迴時記錄當前區間左側所有數之和即可。

對於第三條轉移,本質上與第二條轉移沒有區別。

因此這個轉移的過程就被我們線上段樹合併的同時優化掉了,複雜度 \(O(n \log n)\)

#include <bits/stdc++.h>
using namespace std;
#define ls t[p].l
#define rs t[p].r
#define mid (l + r >> 1)
#define rep(i, l, r) for (int i = l; i <= r; ++i)
#define Next(i, u) for (int i = h[u]; i; i = e[i].next)
const int N = 500000 + 5;
const int Mod = 998244353;
struct tree { int sum, tag, l, r;} t[N * 40];
struct edge { int v, next;} e[N << 1];
int n, m, u, v, tot, cnt, h[N], rt[N], dep[N], val[N];
int read() {
    char c; int x = 0, f = 1;
    c = getchar();
    while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int Inc(int a, int b) { return (a += b) >= Mod ? a - Mod : a;}
int Dec(int a, int b) { return (a -= b) < 0 ? a + Mod : a;}
int Mul(int a, int b) { return 1ll * a * b % Mod;}
void add(int u, int v) {
    e[++tot].v = v, e[tot].next = h[u], h[u] = tot;
    e[++tot].v = u, e[tot].next = h[v], h[v] = tot;
}
void Prefix(int u, int fa) {
    dep[u] = dep[fa] + 1;
    Next(i, u) if(e[i].v != fa) Prefix(e[i].v, u);
}
void down(int p) {
    t[ls].sum = Mul(t[ls].sum, t[p].tag), t[rs].sum = Mul(t[rs].sum, t[p].tag);
    t[ls].tag = Mul(t[ls].tag, t[p].tag), t[rs].tag = Mul(t[rs].tag, t[p].tag);
    t[p].tag = 1;
}
void update(int &p, int l, int r, int x, int y, int k) {
    if(!p) p = ++cnt, t[p].tag = 1; t[p].sum += k;
    if(l == r) return;
    if(mid >= x) update(ls, l, mid, x, y, k);
    if(mid < y) update(rs, mid + 1, r, x, y, k);
}
void modify(int &p, int l, int r, int x, int y) {
    if(!p) p = ++cnt, t[p].tag = 1;
    if(l == r) { t[p].sum = 0; return;}
    down(p);
    if(mid >= x) modify(ls, l, mid, x, y);
    if(mid < y) modify(rs, mid + 1, r, x, y);
    t[p].sum = Inc(t[ls].sum, t[rs].sum);
}
void Merge(int &p, int k, int l, int r, int S1, int S2, int S) {
    if(!p || !k) {
        if(!p && !k) return;
        if(!p) p = p + k, t[p].sum = Mul(t[k].sum, S1), t[p].tag = Mul(t[p].tag, S1);
        else t[p].sum = Mul(t[p].sum, Inc(S2, S)), t[p].tag = Mul(t[p].tag, Inc(S2, S));
        return ;
    }
    if(l == r) { 
        S1 = Inc(S1, t[p].sum), S2 = Inc(S2, t[k].sum);
        int tmp = Mul(t[p].sum, t[k].sum);
        t[p].sum = Inc(Mul(t[k].sum, S1), Mul(t[p].sum, Inc(S, S2))); 
        t[p].sum = Dec(t[p].sum, tmp);
        return ;
    }
    down(p), down(k);
    Merge(rs, t[k].r, mid + 1, r, Inc(S1, t[ls].sum), Inc(S2, t[t[k].l].sum), S);
    Merge(ls, t[k].l, l, mid, S1, S2, S);
    t[p].sum = Inc(t[ls].sum, t[rs].sum);
}
int query(int p, int l, int r, int x, int y) {
    if(!p) return 0;
    if(l >= x && r <= y) return t[p].sum;
    down(p);
    int ans = 0;
    if(mid >= x) ans = Inc(ans, query(ls, l, mid, x, y));
    if(mid < y) ans = Inc(ans, query(rs, mid + 1, r, x, y));
    return ans;
}
void dfs(int u, int fa) {
    update(rt[u], 0, n, val[u], val[u], 1);
    Next(i, u) { 
        int v = e[i].v; if(v == fa) continue;
        dfs(v, u), Merge(rt[u], rt[v], 0, n, 0, 0, t[rt[v]].sum);
    }
    modify(rt[u], 0, n, dep[u], dep[u]);
}
int main() {
    n = read();
    rep(i, 1, n - 1) u = read(), v = read(), add(u, v);
    Prefix(1, 0);
    m = read();
    rep(i, 1, m) u = read(), v = read(), val[v] = max(val[v], dep[u]);
    dfs(1, 0);
    printf("%d", t[rt[1]].sum);
    return 0;
}

\(dp\) 狀態已經超過要求後,如果存在某一維初始值比較少,整體 \(dp\) 不失一個好的選擇。