@(K ACMer)
A. Wizards’ Duel
题意说了一大堆…就是一个简单地运算.
B. Rebranding
题意
给你一个字符串,然后有m个操作,形如:
a b
这样的二元组,就是把字符串中为a的换为b,为b的换为a.
分析
这里字符串比较大,直接模拟相必要超时.
不过这个很明显,只需要用一个大小为26的数组,维护这个字母最终变为了什么就好了,复杂度是
O(26∗n)
.如果再加一个大小为26的数组,作为位置标记,那么就可以在
O(n)
的复杂度完成了.
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e5 + 20;
char a[30];
int b[30];
int main(void) {
int n, m;
cin >> n >> m;
string str;
cin >> str;
for (int i = 0; i < 26; i++)
a[i] = 'a' + i, b[i] = i;
for (int i = 0; i < m; i++) {
char x, y;
cin >> x >> y;
if (x == y) continue;
a[b[x - 'a']] = y;
a[b[y - 'a']] = x;
swap(b[y - 'a'] , b[x - 'a']);
}
for (int i = 0; i < n; i++) {
str[i] = a[str[i] - 'a'];
}
cout << str << endl;
return 0;
}
C. Median Smoothing
题意
给你一个01序列a,每次遵循以下规则变换,最左边的后最右边的不变,然后新的a[i],为原来序列中
a[i−1],a[i],a[i+1]
的中位数.然后这个序列变换一定次数后就会保持不变了,问你变换多少次后,序列保持不变,并输出这个序列的样子.
分析
可以观察到
1.....1
最终一定会变成
11111111
1.....0
最终一定会变成
111110000
这时候只需要求其中的孤立0或1的个数就是变换次数.比如
1110101010
其中孤立的1的个数就是三个.
这个思路下去,就只需要写一个搜索…然而有各种细节需要处理,很麻烦…最后五分钟才提交AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e5 + 20;
int a[5 * maxn];
int n;
int ans = 0;
void dfs(int s) {
for (; s < n - 1; s++)
if (a[s + 1] != a[s]) break;
if (s == n - 1) return;
int e, x = 0, y = 0;
for (e = s + 1; e < n; e++) {
if (a[e] == a[e - 1] || e == n - 1) break;
if (a[e] == 0) x++;
else y++;
}
if (a[e] == 1) ans = max(ans, x);
else ans = max(ans, y);
for (int i = s, j = e; i <= j; i++, j--) {
a[i] = a[s];
a[j] = a[e];
if (i == j) a[i] = a[e];
}
dfs(e);
}
int main(void) {
scanf("%d", &n);
ans = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
dfs(0);
printf("%d\n", ans);
for (int i = 0; i < n; i++) {
if (i) printf(" ");
printf("%d", a[i]);
}
printf("\n");
return 0;
}
D. Chip ‘n Dale Rescue Rangers(二分 + 物理)
题意
一艘船要从坐标
(a,b)
行驶到坐标
(c,d)
,最大速度为v.但是期间会刮风,风会给船x方向和y方向的分速度,前t分钟是向量为
(vx,vy)
的风,后t分钟是向量为
(wx,wy)
的风.问船所需要的最小时间到达目标点是多少?
分析
首先这样直接求这个最小时间显然是很难的,但是我们把问题转化为:已知时间t,问能否在这个时间到达目的点?这样只需二分的来假设这个时间t就可以了.
好…那么问题来了,已知时间t和最大速度v就可以得出,这艘船靠自己最多可以行驶
(v∗t)
的距离
maxs
.
但是这样仍然不好算..各种分速度各种阶段的..
这时候…..
物理大法
的威力就来了!我们可以分解为x和y来算,而且还可以把本来同时进行的动作分出一个先后顺序,我们让两股风先吹,看把船能挂到那个地方去,然后这个地方和终点的距离如果满足小于
maxs
,那么就可以在
t
的时间到达….
对于一些没法直接按照贪心策略,一步求出最优解的问题,如果解的大小满足二分的比较性质,我们就用二分答案的方法来解决
code
#include<cmath>
#include<iomanip>
#include<iostream>
#include<algorithm>
using namespace std;
double x, y, x2, y2, v, t, vx, vy, wx, wy;
bool ok(double a) {
double sx, sy;
if (a <= t) sx = vx * a, sy = vy * a;
else sx = vx * t + (a - t) * wx, sy = vy * t + (a - t) * wy;
sx = x2 - x - sx, sy = y2 - y - sy;
if (a * v * a * v + 1e-6 >= sx * sx + sy * sy) return true;
else return false;
}
int main(void) {
cin >> x >> y >> x2 >> y2 >> v >> t >> vx >> vy >> wx >> wy;
double l = 1e-9, r = 1e10;
for (int i = 0; i < 150; i++) {
double mid = (l + r) / 2;
if (ok(mid)) r = mid;
else l = mid;
}
cout << setprecision(16) << l << endl;
}
E. Three States
题意
给你一个离散的矩阵地图,图中1,2,3是三个国家的块区域,’.’是可以修建路的,’#’是不能走的.问要让这三个块相互连通,至少要在多少个点上修建道路?
分析:
最直接的解法是从三个国家的块出发,做三个队列,实现三个方向的搜索,交替更新队列即可,但是这样实现复杂,可以分为三次,都全部搜索,再枚举三个路径的交点.
定义
然后直接用bfs暴力更新这个dp即可.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = int(1e9) + 7, INF = 0x3ffffff, maxn = 1e3 + 40;
int n, m;
char G[maxn][maxn];
bool used[maxn][maxn];
int dp[3][maxn][maxn], dirx[4] = {-1, 1, 0, 0}, diry[4] = {0, 0, -1, 1};
void bfs(char c) {
queue<pair<int, int> > q;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (G[i][j] == c) {
q.push(make_pair(i, j));
dp[c - '1'][i][j] = 0;
}
while (!q.empty()) {
pair<int, int> t = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int x = t.first + dirx[i], y = t.second + diry[i];
if (x < 1 || y < 1 || x > n || y > m || G[x][y] == '#') continue;
if (dp[c - '1'][x][y] > dp[c - '1'][t.first][t.second] + (G[t.first][t.second] == '.')) {
dp[c - '1'][x][y] = dp[c - '1'][t.first][t.second] + (G[t.first][t.second] == '.');
q.push(make_pair(x, y));
}
}
}
}
int main(void) {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> G[i][j];
for (int i = 0; i < 3; i++)
for (int j = 0; j <= n; j++)
for (int k = 0; k <= m; k++)
dp[i][j][k] = INF;
for (int i = 0; i < 3; i++) bfs(i + '1');
int ans = INF;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
ans = min(ans, dp[0][i][j] + dp[1][i][j] + dp[2][i][j] + (G[i][j] == '.'));
cout << (ans == INF ? -1 : ans) << endl;
return 0;
}