1. 程式人生 > 實用技巧 >19級暑假第二場訓練賽

19級暑假第二場訓練賽

A題 CodeForces - 1234A

Example

Input

3
5
1 2 3 4 5
3
1 2 2cpp
4
1 1 1 1

Output

3
2
1

想複雜了,直接計算平均值向上取整

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int a[N], t, n;
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> t; while (t--) {
		int sum = 0;
		cin >> n;
		for (int i = 1; i <= n; ++i)cin >> a[i], sum += a[i];
		int p = sum / n * n >= sum ? sum / n : sum / n + 1;
		cout << p << endl;
	}
}

B題 CodeForces - 1234B2

Examples

Input

7 2
1 2 3 2 1 3 2

Output

2
2 1 

Input

10 4
2 3 3 1 1 2 1 2 3 3

Output

3
1 3 2 

B題和C題是一樣的只需要考慮資料規模即可

C題資料範圍 \(1 <= d_i <= 10^9\)

思路:

根據題意,用佇列模擬下,set儲存目前顯示的訊息內容

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
deque <ll> q;
set <ll> s;
int main() {
	//freopen("in.txt", "r", stdin);
        int n, k;
	cin >> n >> k;
	for (int i = 1, x; i <= n; i++) {
		cin >> x;
		if (s.find(x) != s.end()) continue;//如果存在就跳過
		s.insert(x);
		q.push_front(x);
		if (q.size() > k) {
			s.erase(q.back());
			q.pop_back();
		}
	}
	cout << q.size() << '\n';
	for (auto x : q)
		cout << x << ' ';
}

D題:

CodeForces - 1234C

寫的時候考慮不完全,這道題,我們可以把序號1、2的看成是一樣的,再把序號3、4、5、6看成是一樣的,所以在這裡我看成了1號整體與2號整體。

然後,其實我們不難發現,路徑是唯一的,也就是說我們的走法是唯一的,我們只需要判斷下一步是不是還可以走就可以了。還有到達終點的過程。

AC程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxN = 2e5 + 7;
int N, dir[3][maxN];
char op[3][maxN];
inline bool dfs(int x, int y, int las_op, int lx, int ly){
    if (x == N + 1 && y == 1) return true;
    if (x > N || y > 2 || y < 1) return false;
    if (dir[y][x] == 1){
        if (lx == x) return false;
        return dfs(x + 1, y, 1, x, y);
    }
    else {
        if (lx == x) return dfs(x + 1, y, 2, x, y);
        else return dfs(x, 3 - y, 2, x, y);
    }
}
int main(){
    freopen("in.txt", "r", stdin);
    int T; scanf("%d", &T);
    while (T--) {
        scanf("%d", &N);
        for (int i = 2; i >= 1; i--) scanf("%s", op[i] + 1);
        for (int i = 1; i <= 2; i++) {
            for (int j = 1; j <= N; j++){
                if (op[i][j] <= '2') dir[i][j] = 1;
                else dir[i][j] = 2;
            }
        }
        bool flag;
        if (dir[2][1] == 1) flag = dfs(2, 2, 1, 1, 2);
        else flag = dfs(1, 1, 2, 1, 2);
        printf(flag ? "YES\n" : "NO\n");
    }
    return 0;
}

E題:

CodeForces - 1234D

線段樹、set容器

最先做的時候使用set容器但沒剪枝,直接在大資料TLE,改用26個字母的線段樹才過

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 100;
char str[maxn];
struct node {
	int l, r, sum;
}tr[26][maxn << 2];

void build(int root, int l, int r) {
	for (int i = 0; i < 26; i++) {
		tr[i][root].l = l; tr[i][root].r = r; tr[i][root].sum = 0;
	}
	if (l == r)//重合返回即可
		return;
	int mid = (l + r) >> 1;
	build(root << 1, l, mid);
	build(root << 1 | 1, mid + 1, r);
}

void update(int root, int trnum, int pos, int num) {
	if (tr[trnum][root].l == tr[trnum][root].r) {
		tr[trnum][root].sum += num;
		return;
	}
	int mid = (tr[trnum][root].l + tr[trnum][root].r) >> 1;
	if (pos <= mid) {
		update(root << 1, trnum, pos, num);
	}
	else {
		update(root << 1 | 1, trnum, pos, num);
	}
	tr[trnum][root].sum = tr[trnum][root << 1].sum + tr[trnum][root << 1 | 1].sum;
}

int query(int root, int trnum, int L, int R) {
	if (tr[trnum][root].l == L && tr[trnum][root].r == R)
		return tr[trnum][root].sum;
	int mid = (tr[trnum][root].l + tr[trnum][root].r) >> 1;
	if (R <= mid)
		return query(root << 1, trnum, L, R);
	else if (L > mid)
		return query(root << 1 | 1, trnum, L, R);
	else
		return query(root << 1, trnum, L, mid) + query(root << 1 | 1, trnum, mid + 1, R);

}

int main() {
	//freopen("in.txt", "r", stdin);
	int n, m, opt, x, y;
	char ss[5]; str[0] = '#';
	scanf("%s", &str[1]);
	n = strlen(str) - 1;
	build(1, 1, n);
	cin >> m;
	for (int i = 1; i <= n; i++) {
		update(1, str[i] - 'a', i, 1);
	}
	while (m--) {
		cin >> opt;
		if (opt == 1) {
			cin >> x >> ss;
			if (str[x] != ss[0]) {
				update(1, str[x] - 'a', x, -1);
				update(1, ss[0] - 'a', x, 1);
				str[x] = ss[0];
			}
		}
		else {
			cin >> x >> y;
			int c = 0;
			for (int i = 0; i < 26; i++) {
				if (query(1, i, x, y)) {
					c++;
				}
			}
			printf("%d\n", c);
		}
	}
}

貼一下dalao的set容器寫法,作為學習

思路:這裡用到了一個比較巧妙的技巧,用26個set來儲存每個字母在字串中出現的位置,因為STL中set是排序的,所以每次查詢時,只需要遍歷26個字母,查詢其在字串中第一次出現的在l之後的位置,若該位置比r要小,說明這個字元存在於這個區間之內,答案加1。更新時只需要在原串位置的字元對應的set中去除這個位置,並在新替換的字元對應的set中存入該位置即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5+10;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
char s[maxn];
int q;
set<int> Set[26];
int main()
{
	scanf("%s", s+1);
	cin >> q;
	int n = strlen(s+1);
	for (int i = 1; i <= n; i++) 
		Set[s[i]-'a'].insert(i);
	for (int i = 0; i < q; i++) {
		int op;
		cin >> op;
		if (op == 1) {
			int p; char c;
			scanf("%d %c", &p, &c);
			int cur = s[p]-'a';
			if (Set[cur].count(p))
				Set[cur].erase(Set[cur].find(p));
			s[p] = c;
			Set[c-'a'].insert(p);
		} else {
			int l, r, ans = 0;
			scanf("%d%d", &l, &r);
			for (int j = 0; j < 26; j++) {
				int cur = *Set[j].lower_bound(l);
				if (cur >= l && cur <= r) {
					ans++;
				}
			}
			cout << ans << "\n";
		}
	}
	return 0;
}