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;
}