A. Vitaliy and Pie
给你一个字符串,奇数位上是小写字母,偶数位上是大写字母,小写字母表示钥匙的类型能打开对应大写字母的门,
大写字母表示门的种类,问之前还要买多少把钥匙,才能走完。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 const int maxn = 1e5 + 10; char str[maxn * 2]; int cnt[maxn * 2]; int main() { int n; int ans = 0; memset(cnt, 0, sizeof(cnt)); cin >> n; cin >> str + 1; for (int i = 1; i <= 2 * n - 2; i++){ if (i & 1){ int t = str[i] - 'a'; cnt[t]++; } else{ int t = str[i] - 'A'; if (cnt[t] == 0){ ans++; continue; } cnt[t]--; } } cout << ans << endl; return 0; }
B. Pasha and String
给出一个字符串,然后m个东西,每个东西一个数字a[i], 将 [a[i],|s| - a[i]+1] 的区间内的字符串倒置,输出最后的串的样子。
因为是关于中点对称的,所以就记录每个点被覆盖的 次数,然后从左向中枚举,如果覆盖次数为奇数则交换a[i] ,a[s-i+1]。因为蠢了写了个线段树。。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn = 2 * 100000 + 10; char str[maxn]; int color[maxn << 2]; void build(int l, int r, int rt) { color[rt] = 0; if (l == r) return; int mid = (l + r) >> 1; build(lson); build(rson); } void down(int rt) { if (color[rt]){ color[rt << 1] ^= 1; color[rt << 1 | 1] ^= 1; color[rt] = 0; } } void update(int L, int R, int l, int r, int rt) { if (L <= l&&r <= R){ color[rt] ^= 1; return; } down(rt); int mid = (l + r) >> 1; if (L <= mid) update(L, R, lson); if (R>mid) update(L, R, rson); } int ask(int key, int l, int r, int rt) { if (l == r) return color[rt]; down(rt); int mid = (l + r) >> 1; if (key <= mid) return ask(key, lson); else return ask(key, rson); } int main() { int m, a; scanf("%s", str + 1); int len = strlen(str + 1); cin >> m; build(1, len, 1); for (int i = 0; i<m; i++){ scanf("%d", &a); update(a, len - a + 1, 1, len, 1); } for (int i = 1; i <= len / 2; i++){ int t = ask(i, 1, len, 1); if (t) swap(str[i], str[len - i + 1]); } for (int i = 1; i <= len; i++) printf("%c", str[i]); cout << endl; return 0; }
C. Ilya and Sticks
给出那么多根长度的火柴,每个火柴长度可以减1,也可以不减,四个火柴a,a,b,b类的可以拼成一个矩阵,问最后可以拼成的矩阵的和最大是多少?
从高到低排序,然后贪心搞下就好了。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; typedef long long LL; LL cmp(const LL &a, const LL &b) { return a>b; } const int maxn = 1e5 + 10; int a[maxn]; int q[maxn]; int main() { int n; cin >> n; for (LL i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1, cmp); LL ans = 0; LL len = 0; LL l, r; for (LL i = 1; i<n; i++){ q[len++] = a[i]; if (a[i] == a[i + 1] || a[i] == a[i + 1] + 1){ q[len++] = a[i + 1]; i++; continue; } len--; } for (LL i = 0; i<len - 3; i += 4){ if (q[i] == q[i + 1]) l = q[i]; else l = q[i + 1]; if (q[i + 2] == q[i + 3]) r = q[i + 2]; else r = q[i + 3]; ans += l*r; } cout << ans << endl; return 0; }
D. Arthur and Walls
给出一个n*m的图,*表示墙,.表示房间,问至少去了多少个*使得最后连通的房子中间没有墙这个东西,要求输出任意一副满足条件的图。
把分成2*2的小方格,如果2*2的小方格李有一个*,那么这个*就要变成. 。最后使得不存在有2*2的小方格内只有一个*。比赛的时候没有想到,
赛后还是没有想到,原本想的是把所有连通的最边界的四个顶点内的点全变为.。然后继续判,知道所有连通的图内不存在*为止。这个复杂度有点爆表。若是这个图合法,那么就不存在2*2的小方格里有一个*,分治搞,不好想,挺厉害的。为了省事,各种越界,a了。。无语。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> #include <stdlib.h> #include <cstdlib> using namespace std; #define INF 1000000000 int dx[] = { -1, -1, -1, 0, 1, 1, 1, 0 }; int dy[] = { -1, 0, 1, 1, 1, 0, -1, -1 }; const int maxn = 2222; char str[maxn][maxn]; int vis[maxn][maxn]; int judge(int x, int y) { if (str[x][y] == '.') return 0; if (str[x - 1][y - 1] == '.'&&str[x - 1][y] == '.'&&str[x][y - 1] == '.') return 1; if (str[x - 1][y] == '.'&&str[x - 1][y + 1] == '.'&&str[x][y + 1] == '.') return 1; if (str[x][y + 1] == '.'&&str[x + 1][y + 1] == '.'&&str[x + 1][y] == '.') return 1; if (str[x + 1][y] == '.'&&str[x + 1][y - 1] == '.'&&str[x][y - 1] == '.') return 1; return 0; } struct Node { int x; int y; }; queue<Node> q; int main() { memset(vis, 0, sizeof(vis)); int n, m; cin >> n >> m; for (int i = 0; i < n; i++) scanf("%s", str[i]); for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++){ if (judge(i, j)){ Node t; t.x = i; t.y = j; q.push(t); } } } while (!q.empty()){ Node cur = q.front(); int x = cur.x; int y = cur.y; q.pop(); if (vis[x][y])continue; vis[x][y] = 1; //printf("%d %d ",x,y); str[x][y] = '.'; for (int i = 0; i < 8; i++){ int xx = x + dx[i]; int yy = y + dy[i]; if (xx >= 0 && yy >= 0 && xx<n&&yy<m){ if (judge(xx, yy)){ Node k; k.x = xx; k.y = yy; q.push(k); } } } } for (int i = 0; i < n; i++){ for (int j = 0; j < m; j++) printf("%c", str[i][j]); cout << endl; } return 0; }
E. Anya and Cubes
题意:n个数随便取,最多使得取得数里面的t个不超过k个变成其阶层的形式,使得最后和为s的方法数。
比赛的时候随便写了个暴力,就睡了。
此题用中途相遇法搞下,从中间折半,把左边搜到的值hash一下。在从右边搜,每次搜到一个S时,把hash表里值为 s - S且用的t不超过的k的的种类数相加.
赛后用map水过,注意用map<int,int> m; 用m[5] 判断 ,和m.count(5) ;判断5这个键值存在不存在时候,是有时间差距的,m[5]直接访问如果不存在,则会插入一个0进去,这样会多了许多无用的值。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <string> #include <vector> #include <cmath> #include <queue> #include <map> #include <set> using namespace std; #define INF 1000000000 //typedef __int64 LL; typedef long long LL; int up; LL s; LL k, len1, len2; LL chart[100]; map<int, LL> m[30]; LL val; int a[100]; LL jie(int x) { LL ans = 1; for (int i = 1; i <= x; i++) ans *= i; return ans; } int gao(LL x) { for (int i = 1; i <= 100; i++){ if (jie(i)>x){ return i - 1; } } } void init() { for (int i = 1; i <= up; i++){ chart[i] = jie(i); } } void dfs(int x, int ans, LL sum) { if (x == len1 + 1){ //printf("%d %d ",k-ans,sum); m[k - ans][sum]++; return; } dfs(x + 1, ans, sum); if (sum + a[x] <= s) dfs(x + 1, ans, sum + a[x]); if (a[x] <= up&&chart[a[x]] + sum <= s&&ans){ dfs(x + 1, ans - 1, sum + chart[a[x]]); } } void DFS(int x, int ans, LL sum) { if (x == len2 + 1){ //printf("%d %d ",k-ans,sum); for (int i = 0; i <= ans; i++) if (m[i].count(s - sum)) val += m[i][s - sum]; return; } DFS(x + 1, ans, sum); if (sum + a[x + len1] <= s) DFS(x + 1, ans, sum + a[x + len1]); if (a[x + len1] <= up&&chart[a[x + len1]] + sum <= s&&ans){ DFS(x + 1, ans - 1, sum + chart[a[x + len1]]); } } int main() { int n; val = 0; cin >> n >> k >> s; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); up = gao(s); init(); len1 = n / 2; len2 = n - len1; dfs(1, k, 0); DFS(1, k, 0); cout << val << endl; return 0; }