19級暑假第二場訓練賽
阿新 • • 發佈:2020-08-05
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; } }
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題:
寫的時候考慮不完全,這道題,我們可以把序號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題:
線段樹、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;
}