2026-08-09~08-14 hetao1733837 的刷题记录

2026-08-09~08-14 hetao1733837 的刷题记录

LGP3808 AC 自动机(简单版)

原题链接:AC 自动机(简单版)

分析

正式开学之后再学吧。

LGP14212 ROI 2016 Day2 二进制输入

原题链接:ROI 2016 Day2 二进制输入

分析

一个 01 01 01 串,扔到字典树上是一个二叉树......然后呢?

前后缀我们都可以按照正着、反着往上放,所以,我们会有一个东西就是说,我们匹配到了哪,我们都会知道到达这里的最小值(不过,这个的局限性在于,我们没有办法多次使用一个串),那咋办?嵌套一个 DP

好吧,我们换一。

LGP13271 NOI2025 机器人

原题链接:NOI2025 机器人

分析

有点......怎么说呢?

就是,我们发现,可以把这个东西的状态看成 ( u , p ) (u,p) (u,p),即我们位于点 u u u,参数为 p p p。状态的数量仅与边的数量有关( p p p 可以取的值有很多,但是,边数是一定的)。那么,我们直接把 ( u , p ) (u,p) (u,p) 和 ( v , p ′ ) (v,p') (v,p′),难道这个 p ′ p' p′ 不应该 ∈ 1 , d e g v \in1,deg_v1,degv 之间吗?呃,感觉 aoao 写错了......那,我们的建图似乎还是 O ( m ) O(m) O(m) 的?好吧,这个......怎么说呢?又是分层图,又是拆状态的,很抽象吧......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 300005;
int c, n, m, k, v[N], w[N], deg[N];
int ans[N];
unordered_map<int, long long> dis[N];
unordered_map<int, bool> vis[N];
vector<pair<int, int>> e[N];
int up(int x, int y){
    return v[y - 1] - v[x - 1];
}
int down(int x, int y){
    return w[x] - w[y];
}
priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>, greater<pair<int, pair<int, int>>>> q;
void dijkstra(){
    memset(ans, 0x3f, sizeof(ans));
    dis[1][1] = 0;
    vis[1][1] = true;
    ans[1] = 0;
    q.push({0, {1, 1}});
    while (!q.empty()){
        auto tmp = q.top();
        q.pop();
        int dist = tmp.first;
        int u = tmp.second.first;
        int p = tmp.second.second;
        if (dis[u].find(p) == dis[u].end() || dis[u][p] != dist){
            continue;
        } 
        if (p != 1 && deg[u]){
            int val;
            if (p > deg[u])
                val = deg[u];
            else    
                val = p - 1;
            if (!vis[u][val] || dist + down(p, val) < dis[u][val]){
                dis[u][val] = dist + down(p, val);
                q.push({dis[u][val], {u, val}});
                vis[u][val] = true;
            }
        }
        if (p < min(k, deg[u])){
            if (!vis[u][p + 1] || dist + up(p, p + 1) < dis[u][p + 1]){
                dis[u][p + 1] = dist + up(p, p + 1);
                q.push({dis[u][p + 1], {u, p + 1}});
                vis[u][p + 1] = true;
            }
        }
        if (deg[u] < p)
            continue;
        auto tmp2 = e[u][p - 1];
        if (!vis[tmp2.first][p] || dist + tmp2.second < dis[tmp2.first][p]){
            dis[tmp2.first][p] = dist + tmp2.second;
            q.push({dis[tmp2.first][p], {tmp2.first, p}});
            ans[tmp2.first] = min(ans[tmp2.first], dis[tmp2.first][p]);
            vis[tmp2.first][p] = true;
        }
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> c;
    cin >> n >> m >> k;
    for (int i = 1; i < k; i++){
        cin >> v[i];
        v[i] += v[i - 1];
    }
    for (int i = 2; i <= k; i++){
        cin >> w[i];
        w[i] += w[i - 1];
    }
    for (int u = 1, to, val; u <= n; u++){
        cin >> deg[u];
        for (int i = 1; i <= deg[u]; i++){
            cin >> to >> val;
            e[u].push_back({to, val});
        }
    }
    dijkstra();
    for (int i = 1; i <= n; i++){
        if (ans[i] == 0x3f3f3f3f3f3f3f3f)
            cout << -1 << " ";
        else
            cout << ans[i] << " ";
    }
}

LGP6775 NOI2020 制作菜品

原题链接:NOI2020 制作菜品

分析

不是,怎么背包?但是,呃......似乎......可以吗?好像不行/ll

我们按照 d d d 升序排序,发现,对于 m ≥ n − 1 m\ge n-1 m≥n−1 始终有解。

我们很容易发现,在 m = n − 1 m=n-1 m=n−1 的时候,总有 d 1 < k d_1<k d1<k, d 1 + d n ≥ k d_1+d_n\ge k d1+dn≥k,构造形如先用 d 1 d_1 d1,剩下的用 d n d_n dn 补全。

在 m ≥ n m\ge n m≥n 的时候, d n ≥ k d_n\ge k dn≥k,让 d n d_n dn 单独出一个,剩下的按照 m = n − 1 m=n-1 m=n−1 做就行了。

对于 m = n − 2 m=n-2 m=n−2,这个情况成立,当且仅当可以找到一个原料的真子集,设其大小为 s z sz sz,其和 s u m = ( s z − 1 ) × k sum=(sz-1)\times k sum=(sz−1)×k,剩下的按照 m = n − 1 m=n-1 m=n−1 做。这个拿一个 bitset 优化背包就行(我怎么觉得直接做就行?)

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 505, M = 5000005;
int T, n, m, k, d[N];
int id1[N], len1;
int id2[N], len2;
bitset<M> dp[N];
bool cmp(int a, int b){
    return d[a] < d[b];
}
void find(int u, int tot){
    if (!u)
        return ;
    int delta = d[u] - k;
    if (tot - delta >= 0 && dp[u - 1][tot - delta]){
        id1[++len1] = u;
        find(u - 1, tot - delta);
    }
    else{
        id2[++len2] = u;
        find(u - 1, tot);
    }
}
void solve(int *id, int len){
    sort(id + 1, id + len + 1, cmp);
    while (len > 1){
        cout << id[1] << " " << d[id[1]] << " " << id[len] << " " << k - d[id[1]] << '\n';
        d[id[len]] -= k - d[id[1]];
        for (int i = 1; i < len; i++)
            id[i] = id[i + 1];
        len--;
        sort(id + 1, id + len + 1, cmp);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    for (int cs = 1; cs <= T; cs++){
        cin >> n >> m >> k;
        for (int i = 1; i <= n; i++){
            cin >> d[i];
        }
        if (m == n - 2){
            int tmp = m * k;
            dp[0].reset();
            dp[0][tmp] = 1;
            for (int i = 1; i <= n; i++){
                int delta = d[i] - k;
                if (delta >= 0)
                    dp[i] = dp[i - 1] | (dp[i - 1] << delta);
                else
                    dp[i] = dp[i - 1] | (dp[i - 1] >> (-delta));
            }
            if (!dp[n][tmp - k]){
                cout << -1 << '\n';
                continue;
            }
            len1 = len2 = 0;
            find(n, tmp - k);
            solve(id1, len1);
            solve(id2, len2);
        }
        else{
            for (int i = 1; i <= n; i++)
                id1[i] = i;
            sort(id1 + 1, id1 + n + 1, cmp);
            while (m >= n && m){
                int mx = id1[n];
                cout << mx << " " << k << '\n';
                d[mx] -= k;
                if (!d[mx])
                    n--;
                sort(id1 + 1, id1 + n + 1, cmp);
                m--;
            }
            solve(id1, n);
        }
    }
}

LGP3702 SDOI2017 序列计数

原题链接:SDOI2017 序列计数

分析

然后,那个和之类的直接 DP 就可以了。

对,如果和要求正好是某个值,我们可以直接插板。

我们设 P i , j P_{i,j} Pi,j 表示 i i i 个数 m o d    p \mod {p} modp 为 j j j 的方案数, c n t i cnt_{i} cnti 表示 1 , m 1,m 1,m 中 m o d    p \mod p modp 等于 i i i 的个数。

那么,转移形如:

P i , j = ∑ k P i − 1 , k P_{i,j}=\sum\limits_{k}^{}{P_{i-1,k}} Pi,j=k∑Pi−1,k

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 20170408
using namespace std;
const int N = 205, M = 20000005;
struct mat{
    int m, n, ma[N][N];
    mat(){}
    mat(int _m, int _n) : m(_m), n(_n){
        memset(ma, 0, sizeof(ma));
    }
	friend mat operator * (mat a, mat b){
		mat res = mat(a.m, b.n);
		for (int i = 1; i <= res.m; i++){
			for (int j = 1; j <= res.n; j++){
				for (int k = 1; k <= a.n; k++){
					res.ma[i][j] = (res.ma[i][j] 
						+ a.ma[i][k] * b.ma[k][j] % mod) % mod;	
				}
			}
		}
		return res;
	} 
	friend mat operator ^ (mat a, int b){
		mat c = a, res = mat(a.m, a.n);
		for (int i = 1; i <= res.m; i++)
			res.ma[i][i] = 1;
		while (b){
			if (b & 1)
				res = res * c;
			c = c * c;
			b >>= 1;
		}
		return res;
	}
}P, Q, V, W;
int n, m, p, cnt[N], cntt[N];
bool prime[M];
int pr[M], tot;
void init(){
	memset(prime, true, sizeof(prime));
	prime[1] = false;
	for (int i = 2; i <= m; i++){
		if (prime[i] == true){
			pr[++tot] = i;
		}
		for (int j = 1; i * pr[j] <= m && j <= tot; j++){
			prime[i * pr[j]] = false;
			if (i * pr[j] == 0)
				break;
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> p;
	for (int i = 0; i < p; i++){
		cnt[i] = m / p;
	}
	for (int i = 1; i <= m % p; i++){
		cnt[i]++;
	}
	P = mat(p, p);
	P.ma[1][1] = cnt[0];
	for (int i = 2; i <= p; i++)
		P.ma[1][i] = cnt[p - i + 1];
	for (int i = 2; i <= p; i++){
		for (int j = 2; j <= p; j++){
			P.ma[i][j] = P.ma[i - 1][j - 1];
		}
		P.ma[i][1] = P.ma[i - 1][p];
	}
	init();
	for (int i = 1; i <= m; i++){
		if (!prime[i])
			cntt[i % p]++;
	}
	Q = mat(p, p);
	Q.ma[1][1] = cntt[0];
	for (int i = 2; i <= p; i++){
		Q.ma[1][i] = cntt[p - i + 1];
	}
	for (int i = 2; i <= p; i++){
		for (int j = 2; j <= p; j++){
			Q.ma[i][j] = Q.ma[i - 1][j - 1];
		}
		Q.ma[i][1] = Q.ma[i - 1][p];
	}
	for (int i = 1; i <= p; i++){
		for (int j = 1; j <= p; j++){
			P.ma[i][j] %= mod;
			Q.ma[i][j] %= mod;
		}
	}
	V = mat(p, 1);
	W = mat(p, 1);
	for (int i = 1; i <= p; i++){
		V.ma[i][1] = cnt[i - 1] % mod;
		W.ma[i][1] = cntt[i - 1] % mod;
	}
	P = (P ^ (n - 1)) * V;
	Q = (Q ^ (n - 1)) * W;
	cout << (P.ma[1][1] - Q.ma[1][1] + mod) % mod;
}

ZYZOJ A.礼物 gift

原题链接:A.礼物 gift

分析

好像是一个图论建模......就是,我们把那个 B i B_i Bi 当成 d e g deg deg 之类的东西......

天啊,就是说,这个部分分给的很奇特,第一档是一个状压 DP,第二档是一个 O ( n 2 ) O(n^2) O(n2),第三档就是正解了。但是,如果说我们放在图上做了,那么,会出现什么呢?

虽然,这个上 JOI 完全可以盒出来吧......

我要不要先想一下 O ( n 2 ) O(n^2) O(n2) 怎么写......那应该是一个更显然的 DP,然后,暴力进行临近的转移......

我们又发现,一个点变更,只会影响其临近的点......难道直接搜吗?复杂度对吗?好像不是很对......

那么,我似乎可以直接算类似于......

就是,我们处理入度,然后,计算一个点所抵达的点......假了......

那么,既然 DP 似乎不是很行,那,我还是贪心一下吧......

但是,贪心似乎也不是很行啊......

反悔,那困难完了。


我们设 d p i , 0 / 1 dp_{i,0/1} dpi,0/1 表示考虑了前 i i i 个点,第 i i i 个点为送出饼干🍪/蛋糕🎂的最大喜悦值,然后在图上转移,就可以获得一定的分数了......

好的,我成功在 T1 获得了 31pts 😭

白瞎了我的图论建模了😭


天啊,我竟然不使用原题机就盒出了这道题。更可悲的是,我从 2014 年开始刷 JOISC 的,这个是 2013 年的/ll

天啊,这个树是一个基环树。

不是,n 个点 n 条边,不是基环树是什么?那,之前那个 DP 式子完全是树上 DP 来的,直接做吧......

失误了,失误了。

搬的 LGP14442 JOISC 2013 礼物 / Presents......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 100005; 
int n;
struct edge{
    int to, nxt, val;
}e[N];
int head[N], tot;
int indeg[N]; 
int fa[N], pts[N], edg[N];
bool rd[N];
void add(int u, int v, int w){
    indeg[v]++;
    e[++tot].to = v;
    e[tot].nxt = head[u];
    e[tot].val = w;
    head[u] = tot;
}
int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y){
    int fx = find(x), fy = find(y);
    edg[fx]++;
    if (fx == fy){
        rd[tot] = true;
        return;
    }
    fa[fx] = fy;
    pts[fy] += pts[fx];
    edg[fy] += edg[fx];
}
int sum[N][2], dp[N][2];
bool vis[N];
void dfs(int u){
    for (int i = head[u]; i; i = e[i].nxt){
        int v = e[i].to;
        if (vis[i]) 
            continue;
        dfs(v);
        dp[u][0] += max(dp[v][0] + e[i].val * sum[u][0],
                        dp[v][1] + e[i].val * sum[u][1]);
        dp[u][1] += max(dp[v][0] + e[i].val * sum[u][1],
                        dp[v][1] + e[i].val * sum[u][0]);
    }
}
vector<int> block[N];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        head[i] = -1;
        fa[i] = i;
        pts[i] = 1;
    }
    for (int i = 1; i <= n; i++){
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        sum[i][0] = c;
        sum[i][1] = d;
        add(a, i, b);
        merge(a, i);
    }
    for (int i = 1; i <= n; i++){
        block[find(i)].push_back(i);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++){
        if (find(i) != i) 
            continue;
        if (pts[i] - 1 == edg[i]){
            for (int root : block[i]) {
                if (!indeg[root]){
                    dfs(root);
                    ans += max(dp[root][0], dp[root][1]);
                    break;
                }
            }
        } 
        else{
            int tu, tv, tw;
            bool found = false;
            for (int u : block[i]){
                for (int j = head[u]; j != -1; j = e[j].nxt){
                    if (rd[j]){
                        tu = u;
                        tv = e[j].to;
                        tw = e[j].val;
                        vis[j] = true;
                        found = true;
                        break;
                    }
                }
                if (found) 
                    break;
            }
            dp[tu][1] = 0xc0c0c0c0c0c0c0c0;
            dfs(tv);
            int tmp = max(dp[tv][1] + tw * sum[tu][1],
                          dp[tv][0] + tw * sum[tu][0]);
            for (int u : block[i]) dp[u][0] = dp[u][1] = 0;
            dp[tu][0] = 0xc0c0c0c0c0c0c0c0;
            dfs(tv);
            ans += max({tmp,
                        dp[tv][0] + sum[tu][1],
                        dp[tv][1] + sum[tu][0]});
        }
    }
    cout << ans;
}

ZYZOJ B.循环移位 string

原题链接:B.循环移位 string

分析

期望是认真的吗/xia

其实吧......嗯......也......比较困难......

感觉这个更类似与省选场。


天啊,为什么这么难/ll

我真的能推出来式子吗/ll

天啊,我竟然不知道每个字符串的长度需要用在哪/ll

哦,天啊,我来思考一下。

那么,我应该设的期望 DP 就是设 d p i , j dp_{i,j} dpi,j 表示正确了 i i i 个,一共有 j j j 种 F ( S ) F(S) F(S) 的取值时的期望。天啊,这个真的有前途吗?而且,这个怎么转移?更可怕的是,这个东西他要是按照前多少个的话,似乎更没法转移。


等一下,他的输出顺序是一定的/jk

也就是说,我设 d p i dp_{i} dpi 表示对了 i i i 个,那么,有多少种情况呢?

要不还是再加一维吧,我没有演草纸/ll

好吧,我又回到了,假设......不行,因为这个并不统一啊/ll

算了,还是这样弄吧。我们假设 c n t i cnt_i cnti 表示长度大于等于 i i i 的字符串的个数。

那么,我们设 d p i dp_{i} dpi 表示有 i i i 个正确的期望。

问题转化为,有 m m m 个数,将最后一位放到开头,与原序列比对,发现有 i i i 个位置是对的。我们发现,连续 x x x 个相同会出现 x − 1 x-1 x−1 个相同的。然后呢?


嗯......我好像除了概率不会算,其他在场上基本想出来完了。而且,和我预估的差不多,算概率的时候需要容斥。

不过,找理由是错误的,我们需要正确面对。然后,这个题其实在 QOJ 上有原。


题目中给出了 pwepwepwe 这个状物,我们发现他是一个规律性的东西,然后,我们有发现,对于一个长度为 ∣ S ∣ |S| ∣S∣ 的串串,如果他的周期的长度为 ∣ T ∣ |T| ∣T∣,那么,他有 ∣ S ∣ ∣ T ∣ \frac{|S|}{|T|} ∣T∣∣S∣ 此机会取到我们想要的位置。

那么,长度为 i i i,且最小周期长度为 i i i 的字符串的个数(不妨设为 f ( i ) f(i) f(i))为:

f ( i ) = 26 i − ∑ j ∣ i j ≠ i f ( j ) f(i)={26}^{i}-\sum\limits_{j|i}^{j\neq i}{f(j)} f(i)=26i−j∣i∑j=if(j)

那么,长度为 k k k,其 F ( S ) = i F(S)=i F(S)=i 的字符串 S S S 的期望 p ( k , i ) p(k,i) p(k,i) 可以为:

p ( k , i ) = ∑ j ∣ k j ≥ i f ( j ) j 26 k p(k,i)=\frac{\sum\limits_{j|k}^{j\ge i}{\frac{f(j)}{j}}}{{26}^{k}} p(k,i)=26kj∣k∑j≥ijf(j)

然后,我们使用一下朴素的乘法原理还有高中概率的部分知识,可知答案为:

∑ p ( k 1 , i ) × p ( k 2 , i ) \sum{p(k_1,i)\times p(k_2,i)} ∑p(k1,i)×p(k2,i)

想要理解前面为什么要除,可以这么理解:因为我们的字符串保证了随机,所以,显然会有重复,我们有多少个位置,就应该把这些除掉。

但是,这个还是 O ( n 2 ) O(n^2) O(n2) 的(剩下的 20pts 真的还有要的必要吗?)。

我来问一问怎么优化吧。


好吧,就是说,我们发现,答案是一坨,一坨,一坨的(就是配对),然后,我们把这些看成一个一个一一对应的,那么,我们拿一个双指针就可以了......

搬的 QOJ1855......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 200005;
int m, n[N];
int pw[N], f[N];
int mx;
int qpow(int a, int b){
    int res = 1;
    while (b){
        if (b & 1) 
            res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
vector<pair<int, int>> p[N];
int solve(int x, int y){
    auto idx = p[x].begin(), idy = p[y].begin();
    int res = 0, cur = 0;
    while (idx != p[x].end() && idy != p[y].end()){
        int tp = min(idx->first, idy->first);
        res = (res + idx->second * idy->second % mod * (tp - cur)) % mod;
        if (idx->first == tp) 
            idx++;
        if (idy->first == tp) 
            idy++;
        cur = tp;
    }
    return res % mod;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> m;
    for (int i = 1; i <= m; i++){
        cin >> n[i];
        mx = max(mx, n[i]);
    }
    if (m == 1){
        cout << 1 << '\n';
        return 0;
    }
    pw[0] = 1;
    for (int i = 1; i <= mx; i++){
        pw[i] = pw[i - 1] * 26 % mod;
        f[i] = pw[i] + f[i] % mod + mod;
        for (int j = 2 * i; j <= mx; j += i)
            f[j] -= f[i];
        for (int j = i; j <= mx; j += i)
            p[j].push_back({i, 0});
        f[i] = f[i] * qpow(i, mod - 2) % mod;
    }
    for (int i = 1; i <= mx; i++){
        int inv = qpow(pw[i], mod - 2);
        for (auto &j : p[i])
            j.second = f[j.first] * inv % mod;
        for (int j = (int)p[i].size() - 2; j >= 0; j--)
            p[i][j].second = (p[i][j].second + p[i][j + 1].second) % mod;
    }
    int ans = 0;
    for (int i = 1; i <= m; i++)
        ans = (ans + solve(n[i], n[i % m + 1])) % mod;
    cout << ans % mod;
    return 0;
}

ZYZOJ C.聚会 party

原题链接:C.聚会 party

分析

天啊,我竟然我竟无言以对/ll

搬的 LGP7565 JOISC 2021 ビーバーの会合 2 (Day3) ......

有空再补吧。

这题主要是一个树论里重要的结论:树上一条链(直径之类的),给树新加进去一个点(非插入),该链的端点要么不变,要么变成这个新的点。

ZYZOJ D.星座 star

原题链接:D.星座 star

分析

呃......也就是说,我们要么让所有的星星都变黑,要么,让所有含有保留有星星的矩阵都含有小白船......

天啊,这场困难完了/ll


就是,我们发现,星座的构型,似乎都类似于下面一个星星⭐,上面一个⭐(这好像是废话),不过,当高度逐渐上升,小白船的密度似乎会变小,所以,此时星座的连通性变好了。

那么,我们使用一个并查集记录星星的连通性。拿一个树状数组从下往上扫,每次遇到一个⭐,我们删去它,然后,我们在权值上做一点操作,当遇到更优的时候,做一下反悔。对,没了,但是,aoao 写的是啥啊/ll

哦,他把船......就是他维护了没有船的连通块的左右边界。对,那就可以了。

然后,反悔里面还有一些需要注意的,不要弄重复了。

搬的 LGP7219 JOISC 2020 星座 3......

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 200005;
int n;
vector<int> a[N];
int m;
vector<pair<int, int>> star[N];
struct dsu{
	int fa[N];
	void init(){
		for (int i = 0; i <= n + 1; i++){
			fa[i] = i;
		}
	}
	int find(int x){
		return (x == fa[x]) ? fa[x] : fa[x] = find(fa[x]);
	}
	void merge(int x, int y){
		int fx = find(x), fy = find(y);
		if (fx == fy)
			return ;
		fa[fx] = fy;
	}
}l, r;
int c[N];
void add(int x, int val){
	for (int i = x; i <= n + 1; i += i & (-i))
		c[i] += val;
}
int query(int x){
	int res = 0;
	for (int i = x; i; i -= i & (-i))
		res += c[i];
	return res;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1, A; i <= n; i++){
		cin >> A;
		a[A].push_back(i);
	}
	cin >> m;
	for (int i = 1, X, Y, C; i <= m; i++){
		cin >> X >> Y >> C;
		star[Y].push_back({X, C});
	}
	l.init();
	r.init();
	int ans = 0;
	for (int i = 1; i <= n; i++){
		for (auto tmp : star[i]){
			int pos = tmp.first, val = tmp.second;
			int cur = query(pos);
			if (val <= cur){
				ans += val;
			}
			else{
				ans += cur;
				add(l.find(pos) + 1, val - cur);
				add(r.find(pos), cur - val);
			}
		}
		for (auto tmp : a[i]){
			l.merge(tmp, tmp - 1);
			r.merge(tmp, tmp + 1);
		}
	}
	cout << ans;
}
相关推荐
技术小黑43 分钟前
RNN算法实战系列06 | LSTM 实现糖尿病探索与预测
rnn·算法·lstm
疯狂打码的少年1 小时前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
wabs6662 小时前
关于图论【A*算法 | 卡码网127.骑士的攻击的思考】
数据结构·算法·图论·卡码网·广搜的改进版
CIO_Alliance2 小时前
AI认知系列(3)| 数据、算法、算力、场景四要素协同
人工智能·算法·ipaas·系统集成·企业cio联盟·企业级ai化转型
..Dauntless..3 小时前
手写vector vs std::vector:从功能正确到性能达标
算法
间歇性努力持续性发呆的野生快乐选手3 小时前
栈的性质(进栈,出栈,访问)
数据结构·c++
m0_547486663 小时前
《数据结构与算法》全套PPT课件2026(中国海洋大学)
数据结构·算法
旖旎夜光4 小时前
LeetCode 904:水果成篮(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
怪奇云呼军4 小时前
G.711、Opus 和重采样会拖慢识别吗?闪电智能VoiceAgent 的音频入口怎么选
java·人工智能·python·算法·云计算·音视频