2017 ECNA Regional Contest
2017 ECNA Regional Contest
A
B
C
模拟
int main() {
IOS; string s; cin >> s;
int x = 0, y = 0;
rep(i, 0, s.size() - 2 >> 1) x += s[i] - 'A', y += s[i + (s.size() >> 1)] - 'A';
rep(i, 0, s.size() - 2 >> 1) s[i] = ((s[i] - 'A') + x + (s[i + (s.size() >> 1)] - 'A') + y) % 26 + 'A';
rep(i, 0, s.size() - 2 >> 1) cout << s[i];
return 0;
}
D
栈模拟
int main() {
IOS; string s; cin >> n >> m; stack<int> st;
rep(i, 1, m) {
cin >> s; int x = 0;
if (isdigit(s[0]) || s[0] == '-') {
rep(i, s[0] == '-', s.size() - 1) x = x * 10 + s[i] - '0';
if (s[0] == '-') x = -x;
st.push(k); k = ((k + x) % n + n) % n;
} else {
cin >> x;
while (x > 0 && !st.empty()) k = st.top(), st.pop(), --x;
}
}
cout << k;
return 0;
}
E
考察弗洛伊德和离散化
unordered_map<string, int> st;
bool d[N][N], h[N][N];
int getid(string& s) {
return st.count(s) ? st[s] : st[s] = st.size() + 1;
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) {
string s, op, t; cin >> s >> op >> t;
int x = getid(s), y = getid(t);
if (op[0] == 'i') d[x][y] = 1;
else h[x][y] = 1;
} n = st.size();
rep (i, 1, n) d[i][i] = 1;
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n) if (d[i][k] & d[k][j]) d[i][j] = 1;
rep (k, 1, n) rep (i, 1, n) rep (j, 1, n)
if ((d[i][k] & h[k][j]) | (h[i][k] & d[k][j]) | (h[i][k] & h[k][j])) h[i][j] = 1;
rep (i, 1, m) {
string s, op, t; cin >> s >> op >> t;
cout << "Query " << i << ": ";
int x = getid(s), y = getid(t);
if (max(x, y) > n) cout << "false\n";
else if (op[0] == 'i') cout << (d[x][y] ? "true\n" : "false\n");
else cout << (h[x][y] ? "true\n" : "false\n");
}
return 0;
}
F
一开始写成了重心, 然而并不是
重心是均分分支, 而这道题是找到某个点使得分裂后 对数最多, 那直接枚举每个点就好了
VI h[N];
int sz[N];
ll n1, mxa, mxb;
void dfs(int x, int fa) {
sz[x] = 1; VI a; ll cur = 0, s = 0, mx1 = 0, mx2 = 0;
for (auto y : h[x]) if (y != fa) dfs(y, x), sz[x] += sz[y], a.pb(sz[y]);
a.pb(n + 1 - sz[x]);
for (auto i : a) {
cur += i * s, s += i;
if (mx1 < i) mx2 = mx1, mx1 = i;
else umax(mx2, i);
}
if (umax(n1, cur)) mxa = mx1, mxb = mx2;
}
int main() {
IOS; cin >> n;
rep (i, 1, n) {
int u, v; cin >> u >> v;
h[u].pb(v); h[v].pb(u);
}
dfs(0, -1);
cout << n1 << ' ' << n1 - mxa * mxb;
return 0;
}
G
n很小, 又没到爆搜的地步, 那就朴素的线性dp
f[i][j] 表示在第 i 天能吃 \(m*(2/3)^j\) 热量的情况下最多能吃多少
要么连续吃(第 i + 1 天也吃)则 f[i + 1][j + 1] = max(f[i + 1][j + 1], f[i][j] + min(m, a[i + 1]))
要么隔天吃(第 i + 1 天不吃, i + 2 天吃)则 f[i + 2][j] = max(f[i + 2][j], f[i][j] + min(m, a[i + 2]))
或者连续两天不进食, f[i + 3][0] = max(f[i + 3][0], f[i][j] + max(m, a[i + 3]))
注意到 f[i][0] = max(m, a[i])
ll f[N][N], a[N], d[N];
int main() {
IOS; cin >> n >> m; d[0] = m;
rep (i, 1, n) cin >> a[i], d[i] = d[i - 1] * 2 / 3, f[i][0] = min((ll)m, a[i]);
rep (i, 1, n) rep (j, 0, n) {
rep (k, 1, min(n - i, 2)) umax(f[i + k][j + 2 - k], f[i][j] + min(d[j + 2 - k], a[i + k]));
umax(f[i + 3][0], f[i][j] + min(a[i + 3], (ll)m));
}
cout << *max_element(f[n], f[n] + n + 1);
return 0;
}
H
怎么找都行, 爆搜完事
int d[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}};
char a[N][N];
void dfs(int x, int y) {
a[x][y] = '.';
rep (i, 0, 7) {
int dx = x + d[i][0], dy = y + d[i][1];
if (a[dx][dy] != '#') continue;
dfs(dx, dy);
}
}
int main() {
IOS; cin >> n >> m; rep (i, 1, n) cin >> a[i] + 1;
rep (i, 1, n) rep (j, 1, m) if (a[i][j] == '#') dfs(i, j), ++k;
cout << k;
return 0;
}
I
暴力拼接算式, 再计算
首先要添加括号, 意味着 优先级高的符号链接的前面的数 要和 后面通过低级运算算出的数 运算
一共就3个运算符, 那么最多存在() 或 ()() 不存在 (()), (()) 必定可以拆掉一个括号
d / (a * (b - c)) = d / a * (b - c)
所以我们怎么拼接算是呢?
将要填一个数, 那么可以在前面添加一个 '(' 在添加要添加的 运算数, 然后可以添加一个 ')', 再添加运算符 +-*/, 注意括号的匹配, 且不能连续添加括号[不存在(())]
最后运算中缀串就好了, 去合法的最小代价
stack<int> nums;
stack<char> ops;
bool flag = 1;
void cal() {
int a = nums.top(); nums.pop();
int b = nums.top(); nums.pop();
char c = ops.top(); ops.pop();
switch (c) {
case '+': nums.push(b + a); break;
case '-': nums.push(b - a); break;
case '*': nums.push(b * a); break;
case '/': if (a) flag = flag & (b % a == 0), nums.push(b / a);
else flag = 0, nums.push(2); break;
}
}
void read(int& i, string& s) {
int t = 0;
for (; isdigit(s[i]); ++i) t = t * 10 + s[i] - '0';
nums.push(t); --i;
}
int ask(string s) {
while (!nums.empty()) nums.pop();
while (!ops.empty()) ops.pop(); flag = 1;
s = '(' + s + ')';
for (int i = 0; i < s.size(); ++i)
if (isdigit(s[i])) read(i, s);
else
switch (s[i]) {
case '(': ops.push('('); break;
case '+': case '-': while (ops.top() != '(') cal(); ops.push(s[i]); break;
case '*': case '/': while (ops.top() == '*' || ops.top() == '/') cal(); ops.push(s[i]); break;
case ')': while (!ops.empty() && ops.top() != '(') cal(); ops.pop(); break;
}
return nums.top();
}
int n, m, _, k, a[4], b[4], c[4], x, y;
bool v[4];
string s;
int get() {
memcpy(c, b, sizeof b); int ans = 0;
per(i, 3, 1) if (c[i] != a[i]) {
int k = 0;
rep(j, 0, i - 1) if (c[j] == a[i]) k = j;
rep(j, k, i - 1) swap(c[j], c[j + 1]), ++ans;
}
return ans;
}
int write(string& s, int k) {
string t; while (k) t += k % 10 + '0', k /= 10;
reverse(all(t)); s += t;
}
void addop(string& s, int cur, void(*dfs)(int)) {
s += '+'; dfs(cur + 1); s.back() = '-'; dfs(cur + 1);
s.back() = '*'; dfs(cur + 1); s.back() = '/'; dfs(cur + 1);
s.pop_back();
}
void dfs(int cur) {
if (cur == 4) {
if (x != y) return; s.pop_back();
if (ask(s) == 24 && flag) umin(m, x + get() * 2);
s += '*'; return;
}
if (x == y) {
s += '('; ++x; int len = s.size();
rep(i, 0, 3) if (!v[i]) {
v[i] = 1; write(s, b[cur] = a[i]);
addop(s, cur, dfs); v[i] = 0;
while (s.size() != len) s.pop_back();
}
s.pop_back(); --x;
}
int len = s.size();
rep(i, 0, 3) if (!v[i]) {
v[i] = 1; write(s, b[cur] = a[i]);
if (x > y) { ++y; s += ')'; addop(s, cur, dfs); s.pop_back(); --y; }
addop(s, cur, dfs); v[i] = 0;
while (s.size() != len) s.pop_back();
}
}
int main() {
IOS; cin >> a[0] >> a[1] >> a[2] >> a[3]; m = 2e9; dfs(0);
if (m == 2e9) cout << "impossible";
else cout << m;
return 0;
}
J
模拟
int a[N], b[N], u[N], r[N], t[N], s;
int main() {
IOS; rep (i, 0, 9) cin >> a[i] >> b[i];
rep (i, 0, 9) cin >> u[i] >> r[i] >> t[i];
rep (i, 0, 29) {
if (s >= t[i % 10]) {
int d = s - t[i % 10];
int k = d / (u[i % 10] + r[i % 10]) * (u[i % 10] + r[i % 10]);
t[i % 10] += (k + u[i % 10]); umax(s, t[i % 10]);
t[i % 10] += r[i % 10];
}
s += a[i % 10]; umax(t[i % 10], s); s += b[i % 10];
}
cout << s - b[9] << endl;
}
K
这题是训练的时候随便加的一道题
01分数规划, 二分就行
struct node{ int x, y, z; };
int n, v[N];
vector<node> ve;
double ans, e[N][N], dis[N];
void prim(double x) {
rep (i, 1, n) {
double mi = 2e9; int now;
rep (j, 0, n - 1) if(!v[j] && dis[j] < mi) mi = dis[j], now = j;
v[now] = 1; ans += dis[now];
rep (j, 0, n - 1) dis[j] = min(dis[j], abs(ve[now].z - ve[j].z + 0.0) - x * e[now][j]);
}
}
bool judge(double x) {
rep (i, 0, n - 1) dis[i] = 2e9, v[i] = 0;
dis[0] = 0; ans = 0; prim(x);
return ans > 0;
}
int main() {
while (read(n), n) {
vector<node>().swap(ve);
for (int i = 1, x, y, z; i <= n; ++i) {
cin >> x >> y >> z;
ve.pb(node{x, y, z});
}
rep (i, 0, n - 1) rep (j, 0, n - 1)
e[i][j] = sqrt(0.0 + sqr(ve[i].x - ve[j].x) + sqr(ve[i].y - ve[j].y));
double l = 0, r = 2e9;
while(r - l > eps) {
double mid = (l + r) / 2;
if (judge(mid)) l = mid;
else r = mid;
}
printf("%0.3f\n", r);
}
return 0;
}