A. New Year and Hurry(Codeforces 750A)
思路
先预处理出解每道题所用的时间
a[i]=5i
,再处理前缀和
a[i]+=a[i−1]
,处理完后
a[i]
表示解完
i
道题需要花多少时间。然后令
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
int n, k, d, a[maxn];
int main() {
// freopen("data.txt", "r", stdin);
for(int i = 1; i <= 10; i++) {
a[i] = 5 * i;
}
for(int i = 1; i <= 10; i++) {
a[i] += a[i-1];
}
cin >> n >> k;
d = 240 - k;
for(int i = n; i >= 0; i--) {
if(d >= a[i]) {
cout << i << endl;;
break;
}
}
return 0;
}
B. New Year and North Pole(Codeforces 750B)
思路
在本题中,经度(东西走向)不是我们关心的量,纬度(南北走向)才是我们关心的量。于是我们可以把纬度抽象为一个
x
数轴。当
代码
#include <bits/stdc++.h>
using namespace std;
const int np = 0, sp = 20000;
int n;
bool ok() {
int t, cur = 0;
string s;
for(int i = 1; i <= n; i++) {
cin >> t >> s;
if(s == "South") {
cur += t;
if(cur > sp) {
return false;
}
}
else if(s == "North") {
cur -= t;
if(cur < np) {
return false;
}
}
else {
if(cur == np || cur == sp) {
return false;
}
}
}
return (cur == np);
}
int main() {
// freopen("data.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
puts(ok() ? "YES" : "NO");
return 0;
}
C. New Year and Rating(Codeforces 750C)
思路
首先因为
Div1
的
rating
区间是
[1900,INF]
,所以如果一个人一直在
Div1
里的话,那么他的可能的最大
rating
将是
INF(INF±α=INF)
。
其次,我们可以维护一个区间
[l,r]
,表示当前主角的
rating
在哪个区间内(根据目前已知的信息)。根据每条信息为这个区间,最后
r
就是答案。若
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10, INF = 1e9;
bool ok = true, two = false;
int n, l, r, num[maxn], d[maxn];
int main() {
// freopen("data.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> num[i] >> d[i];
if(d[i] == 2) {
two = true;
}
}
// 当主角一直在Div1中
if(two == false) {
cout << "Infinity" << endl;
return 0;
}
// 设置初始区间
if(d[1] == 1) {
l = 1900;
r = INF;
}
else {
l = -INF;
r = 1899;
}
for(int i = 1; i <= n; i++) {
// 动态维护区间信息
l += num[i];
r += num[i];
if(l < -INF) {
l = -INF;
}
if(r > INF) {
r = INF;
}
// 根据Div的变化情况修正区间
if(i < n) {
// 当主角从Div2到Div2而且rating上升时
if(d[i] == 2 && d[i+1] == 2 && num[i] >= 0) {
r = min(r, 1899);
}
// 当主角从Div1到Div1而且rating下降时
if(d[i] == 1 && d[i+1] == 1 && num[i] < 0) {
l = max(l, 1900);
}
// 当主角从Div1到Div2而且rating下降时
if(d[i] == 1 && d[i+1] == 2 && num[i] < 0) {
r = min(r, 1899);
}
// 当主角从Div2到Div1而且rating上升时
if(d[i] == 2 && d[i+1] == 1 && num[i] >= 0) {
l = max(l, 1900);
}
// 以下两种情况不可能发生
if(d[i] == 1 && d[i+1] == 2 && num[i] >= 0) {
ok = false;
break;
}
if(d[i] == 2 && d[i+1] == 1 && num[i] <= 0) {
ok = false;
break;
}
// 剩余两种情况不用修正
}
// 出现了非法区间
if(l > r) {
ok = false;
break;
}
}
if(ok == false) {
cout << "Impossible" << endl;
}
else if(r >= INF) {
cout << "Infinity" << endl;
}
else {
cout << r << endl;
}
return 0;
}
思路
上述的思路虽然比较严谨,但代码上过于冗杂。如果依状态转移的思想来看,题给的每行输入相当于状态的转移。换句话说,之前增加的 rating 总和与当前的 Div 数决定了上一个状态。所以边输入边转移状态即可。
代码
#include <bits/stdc++.h>
using namespace std;
const int inf = 1e9;
int n, tmp, d, l, r, del;
int main() {
scanf("%d", &n);
l = -inf, r = inf;
del = 0;
for(int i = 0; i < n; i++) {
scanf("%d%d", &tmp, &d);
if(d == 1) {
l = max(l, 1900 - del);
} else {
r = min(r, 1899 - del);
}
del += tmp;
}
if(l > r) {
puts("Impossible");
} else if(r == inf) {
puts("Infinity");
} else {
printf("%d\n", r + del);
}
return 0;
}
D. New Year and Fireworks(Codeforces 750D)
思路
看到图中的类似二叉树的结构,首先想到的是搜索(生成所有的状态(包括阶段信息,位置信息和方向信息)然后涂色),但是粗略估计
O(2n)
的复杂度是在是太高了。但是忽然发现,烟花的运动范围是有限的,假设初始的烟花一直直线运动,也只能运动到
150
个格子之外。这意味着如果我们用平面直角坐标系来刻画烟花的位置信息的话,若烟花的初始位置为
(0,0)
,则烟花能够到的位置
(x,y)
满足
x∈[−150,150],y∈[−150,150]
。那么状态空间的大小就是
8nxy
,其中
8
表示烟花能往八个方向运动。
既然状态空间那么小,我们就可以用记忆化搜索来解决本题。在实现方面,可以用
代码
#include <bits/stdc++.h>
using namespace std;
// 记录八个方向的坐标变化的常量数组
const int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
const int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
const int maxn = 35, maxc = 400;
bool color[maxc][maxc], vis[maxn][maxc][maxc][10];
int n, ans, t[maxn];
// 记忆化搜索
void dfs(int cur, int x, int y, int d) {
int nx, ny, tx, ty, td;
vis[cur][x][y][d] = true;
// color
// 为本格涂色
if(color[x][y] == false) {
color[x][y] = true;
ans++;
}
// 为之后直线运动轨迹上的格子涂色
nx = x;
ny = y;
for(int i = 1; i <= t[cur] - 1; i++) {
nx += dx[d];
ny += dy[d];
if(color[nx][ny] == false) {
color[nx][ny] = true;
ans++;
}
}
if(cur == n) {
return;
}
// 生成向“右前方”分裂的烟花
td = (d + 1) % 8;
tx = nx + dx[td];
ty = ny + dy[td];
if(vis[cur+1][tx][ty][td] == false) {
dfs(cur + 1, tx, ty, td);
}
// 生成向“左前方”分裂的烟花
td = (d + 7) % 8;
tx = nx + dx[td];
ty = ny + dy[td];
if(vis[cur+1][tx][ty][td] == false) {
dfs(cur + 1, tx, ty, td);
}
}
int main() {
// freopen("data.txt", "r", stdin);
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &t[i]);
}
dfs(1, maxc / 2, maxc / 2, 0);
printf("%d\n", ans);
return 0;
}
(其它题目略)