日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

AtCoder Beginner Contest 328 (ABC328)

發布時間:2023/11/16 windows 50 coder
生活随笔 收集整理的這篇文章主要介紹了 AtCoder Beginner Contest 328 (ABC328) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

A. Not Too Hard

模擬。
Code

B. 11/11

模擬。
Code

C. Consecutive

Description

給你一個字符串 \(S\),有 \(Q\) 次詢問,每次輸入 \(l, r\),求:\([S_l,S_r]\) 區間中有多少個相鄰的字符是相等的。

Solution

循環一遍字符串,看看 \(s_i\) 是否等于 \(s_{i+1}\),如果等于,記錄前綴和數組 \(pre\)\(pre_i = pre_{i-1} + 1\),否則 \(pre_i = pre_{i-1}\)

每次詢問的時候只需要輸出 \(pre_{r - 1} - pre_{l - 1}\) 即可。

Code
#include <bits/stdc++.h>

using namespace std;
const int N = 3e5 + 10;

int n, t, l, r, len, c[N];
char s[N];

inline void solve() {
    scanf("%d%d", &l, &r);
    printf("%d\n", c[r - 1] - c[l - 1]);
}

signed main() {
    scanf("%d%d%s", &n, &t, s + 1);
    for (int i = 1; i <= n; i++) c[i] = c[i - 1] + (s[i] == s[i + 1]);
    while (t--) solve();
    return 0;
}

D. Take ABC

Description

給定一個字符串 \(S\),每次會將字符串 \(S\) 中的一個子串 \(\texttt{ABC}\) 刪除,進行若干次操作之后,輸出字符串 \(S\)

Solution

我們維護兩個數組 \(nxt,lst\),分別表示每個字符的后面和前面字符的下標,類似于鏈表的思想。

維護變量 \(z\) 表示當前的下標,當 z != n + 1 的時候進行循環。

每次維護變量 \(t2,t3\) 分別賦值為 nxt[z]nxt[nxt[z]],表示下標 \(z\) 的下一個字符的下標和下一個字符的下一個字符的下標。

如果這三個下標分別對應的字符正好為 \(\texttt{ABC}\),則將 lst[nxt[t3]] 的值更改為 lst[z]nxt[lst[z]] 的值更改為 nxt[t3],表示刪除了當前子串。并且將 \(z\) 指向 lst[z]

每次循環時 z = nxt[z] 即可。

時間復雜度近似于 \(O(n)\)

Code
#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int nxt[N], lst[N], v[N], n;
char s[N];

int main() {
    scanf("%s", s + 1);
    n = strlen(s + 1);
    nxt[0] = 1;
    lst[n + 1] = n;
    for (int i = 1; i <= n; i++)
        nxt[i] = i + 1, lst[i] = i - 1, v[i] = s[i] - 'A' + 1; // 將 nxt 數組和 lst 數組賦初始值,并且 v 數組記錄將字符轉換為數字的結果,方便判斷
    int z = 1, t2, t3;
    while (z != n + 1) {
        t2 = nxt[z];
        t3 = nxt[t2];
        if (t2 == n + 1 || t3 == n + 1) break; // 子串不存在,越界了
        if (v[z] == 1 && v[t2] == 2 && v[t3] == 3) { // 找到子串 "ABC"
            lst[nxt[t3]] = lst[z];
            nxt[lst[z]] = nxt[t3];
            // 如果下標存在,就指向前一個字符
            if (z) z = lst[z];
            if (z) z = lst[z];
            if (z) z = lst[z];
        }
        z = nxt[z];
    }
    // 打印結果
    z = nxt[0];
    while (z != n + 1)
        printf("%c", 'A' - 1 + v[z]), z = nxt[z];
    return 0;
}

E. Modulo MST

Description

給你一個無向圖,求:生成樹中最小的路徑,最小路徑的定義為路徑上的每條邊權值之和 \(\bmod \ K\) 的結果。

Solution

這道題不能用最小生成樹的思想來做,因為加了一個取模的條件,所以不能貪心地取最小的路徑。

所以看到數據范圍 \(1 \le N \le 8,1 \le M \le \dfrac{N(N-1)}{2}\),很明顯可以爆搜。

如果遍歷每條邊,\(M\) 最大為 \(28\),最多有 \(C_{28}^{8}\) 種可能性,大概為 \(10 ^ 6\) 左右,總的時間復雜度為 \(O(C_{28}^{8} \times \log n)\),不會超時。

但是要注意剪枝,可以使用按秩合并的并查集來做,注意不要路徑壓縮,這樣的話就無法在搜索時回溯。

Code
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 20;
int n, m, k, fa[N], si[N];
int x[N << 1], y[N << 1], len[N << 1];

int find(int x) {
	return x == fa[x] ? x : find(fa[x]);
}

int dfs(int i, int cnt, int sum) {
	if (i == m + 1) {
		if (cnt == n - 1) return sum;
		return 1e18;
	}
	int rx = find(x[i]), ry = find(y[i]);
	if (rx == ry) return dfs(i + 1, cnt, sum);
	if (si[rx] > si[ry]) swap(rx, ry);
	fa[rx] = ry;
	si[rx] += si[ry];
	int ans = dfs(i + 1, cnt + 1, (sum + len[i]) % k);
	fa[rx] = rx;
	si[rx] -= si[ry];
	ans = min(ans, dfs(i + 1, cnt, sum));
	return ans;
}

signed main() {
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) fa[i] = i, si[i] = 1;
	for (int i = 1; i <= m; i++) cin >> x[i] >> y[i] >> len[i];
	cout << dfs(1, 0, 0);
	return 0;
}

總結

以上是生活随笔為你收集整理的AtCoder Beginner Contest 328 (ABC328)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。