2014-2015 ACM-ICPC, Asia Tokyo Regional Contest
2014-2015 ACM-ICPC, Asia Tokyo Regional Contest
A | B | C | D | E | F | G | H | I | J | K |
O | O | O | O | O | O |
签到
#include <bits/stdc++.h>
using namespace std; const int N = ;
int b[N], p[N], n, m, cnt[];
int temp[N]; int put(int opt) {
int cnt2[] = {};
int index = ;
for (int i = ; i <= m; i++) {
int num = p[i];
while (num--) {
temp[++index] = opt;
}
opt ^= ;
}
for (int i = ; i <= n; i++) cnt2[temp[i]]++;
if (cnt2[] != cnt[] || cnt2[] != cnt[]) return 1e9;
int j = ;
int res = ;
for (int i = ; i <= n; i++) {
if (b[i] == ) {
while (temp[j] != ) j++;
res += abs(i - j);
j++;
}
}
return res;
} int main() {
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++)
scanf("%d", &b[i]), cnt[b[i]]++;
for (int i = ; i <= m; i++)
scanf("%d", &p[i]);
printf("%d\n", min(put(), put()));
return ;
}
签到
#include <bits/stdc++.h>
using namespace std; char s[];
int res, st[];
int top; int main() {
scanf("%s%d", s + , &res);
int len = strlen(s + );
int ans1 = s[] - '';
for (int i = ; i <= len; i += ) {
if (s[i - ] == '+') {
ans1 += s[i] - '';
} else {
ans1 *= s[i] - '';
}
}
st[++top] = s[] - '';
for (int i = ; i <= len; i += ) {
if (s[i - ] == '*') {
st[top] *= s[i] - '';
} else {
st[++top] = s[i] - '';
}
}
int ans2 = ;
for (int i = ; i <= top; i++) ans2 += st[i];
if (ans1 == res && ans2 == res) puts("U");
else if (ans1 == res) puts("L");
else if (ans2 == res) puts("M");
else puts("I");
return ;
}
如果两个区间存在包含关系,那么肯定直接走到最大的 $d$ 再走到最小的 $c$ 最优。
如果两个区间交叉,那么之间应该是三段距离,分别设为 $a$, $b$, $c$
如果先走左区间再走右区间,那么走的路程为 $a + b + a + b + a + b + c + b + c + b + c= 3a + 5b + 3c$
如果先走右区间再走坐去间,那么走的路程为 $a + b + c + a + b + c + a + b + c = 3a + 3b + 3c$
所以就是把所有交叉的区间合并成一个大区间,然后每次到区间右端点再走回一遍左端点。
用并查集实现即可。
#include <bits/stdc++.h>
using namespace std; const int N = ;
int fa[N], mx[N], mn[N]; int getfa(int x) {
return x == fa[x] ? x : fa[x] = getfa(fa[x]);
} void unit(int x, int y) {
x = getfa(x), y = getfa(y);
if (x == y) return;
fa[x] = y;
mx[y] = max(mx[y], mx[x]);
mn[y] = min(mn[y], mn[x]);
} int main() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) fa[i] = mx[i] = mn[i] = i;
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
for (int i = l; i < r; i++)
unit(i, i + );
}
int ans = n + ;
for (int i = ; i <= n; i++)
if (getfa(i) == i)
ans += (mx[i] - mn[i]) * ;
printf("%d\n", ans);
}
高中物理杀我!!!我高考考的最烂的就是物理了!!!
能不能跨过一个板只跟 $v_y$ 有关。枚举一下要弹多少次,然后二分一下 $v_y$,可以求出 $v_x$,得到的 $v_y$ 不一定使合速度最小,因为合速度是一个对勾函数,三分或者判断一下就行。
#include <bits/stdc++.h>
using namespace std; const int N = ;
const double eps = 1e-;
int d, n, b;
int p[N], h[N];
double loc[N]; int dcmp(double x) {
if (fabs(x) < eps) return ;
return x < ? - : ;
} bool check(int cnt, double vy) {
double per_time = vy * 2.0;
double total_time = per_time * cnt;
double vx = d / total_time;
for (int i = ; i <= cnt; i++) {
double l = loc[i - ], r = loc[i];
for (int j = ; j <= n; j++) {
if (dcmp(p[j] - l) < || dcmp(p[j] - r) > ) continue;
double cur_time = p[j] / vx;
int times = cur_time / per_time;
cur_time -= times * per_time;
if (dcmp(vy * cur_time - 0.5 * cur_time * cur_time - h[j]) < ) return ;
}
}
return ;
} double check0(int cnt, double vy) {
double per_time = vy * 2.0;
double total_time = per_time * cnt;
double vx = d / total_time;
return sqrt(vx * vx + vy * vy);
} int main() {
freopen("in.txt", "r", stdin);
scanf("%d%d%d", &d, &n, &b);
for (int i = ; i <= n; i++)
scanf("%d%d", p + i, h + i);
double ans = 2e4;
for (int i = ; i <= b + ; i++) {
bool flag = ;
if (d % i == ) {
int per = d / i;
for (int j = ; j <= n; j++)
if (p[j] % per == ) {
flag = ;
break;
}
}
if (flag) continue;
double per = 1.0 * d / i;
for (int j = ; j <= i; j++)
loc[j] = per * j;
double l = , r = 2e4;
for (int cnt = ; cnt < ; cnt++) {
double mid = (l + r) / 2.0;
if (check(i, mid)) r = mid;
else l = mid;
}
r = 2e4;
for (int cnt = ; cnt < ; cnt++) {
double ll = l + (r - l) / 3.0, rr = r - (r - l) / 3.0;
if (check0(i, ll) < check0(i, rr)) r = rr;
else l = ll;
}
ans = min(ans, check0(i, l));
}
printf("%.5f\n", ans);
return ;
}
这 $n$ 也出得太小了!!!本质就是求哪些边一定存在于所有最小生成树上。那么就是CF原题了。
#include <bits/stdc++.h>
using namespace std; const int N = 1e5 + ;
int n, m;
struct Edge {
int u, v, cost, id;
bool operator < (const Edge &rhs) const {
return cost < rhs.cost;
}
} edge[N], edge2[N]; struct E {
int v, ne, id;
} e[N];
int head[N], cnt, ans[N]; inline void add(int u, int v, int id) {
e[cnt] = (E){v, head[u], id};
head[u] = cnt++;
e[cnt] = (E){u, head[v], id};
head[v] = cnt++;
} int fa[N], dfn[N], low[N], tol;
int getfa(int x) { return x == fa[x] ? x : fa[x] = getfa(fa[x]); } void dfs(int u, int id) {
low[u] = dfn[u] = ++tol;
for (int i = head[u]; ~i; i = e[i].ne) {
int v = e[i].v;
if (!dfn[v]) {
dfs(v, i);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u]) ans[e[i].id] = ;
} else if (i != (id ^ )) {
low[u] = min(low[u], dfn[v]);
}
}
} inline void unite(int u, int v) {
u = getfa(u);
v = getfa(v);
if (u != v) fa[u] = v;
} int main() {
//freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++) fa[i] = i;
for (int i = ; i < m; i++) {
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].cost);
edge[i].id = i;
}
memcpy(edge2, edge, sizeof(edge2));
sort(edge, edge + m);
for (int i = ; i < m; ) {
int j = i;
while (j + < m && edge[j + ].cost == edge[j].cost) j++;
cnt = tol = ;
for (int k = i; k <= j; k++) {
edge[k].u = getfa(edge[k].u);
edge[k].v = getfa(edge[k].v);
int u = edge[k].u, v = edge[k].v;
head[u] = head[v] = -;
dfn[u] = dfn[v] = low[u] = low[v] = ;
}
for (int k = i; k <= j; k++) {
int u = edge[k].u, v = edge[k].v, id = edge[k].id;
if (u == v) {
//printf("%d\n", k);
ans[id] = ;
continue;
}
ans[id] = ;
add(u, v, id);
}
for (int k = i; k <= j; k++)
if (!dfn[edge[k].u]) dfs(edge[k].u, -);
for (; i <= j; ++i)
unite(edge[i].u, edge[i].v);
}
int ans1 = ;
long long ans2 = ;
for (int i = ; i < m; i++)
if (ans[i] == ) ans1++, ans2 += edge2[i].cost;
printf("%d %lld\n", ans1, ans2);
return ;
}
这道题能写出来是因为大一上学期刚学C语言接触了括号序列判定是否合法的题。当时还没学栈,所以想了一个做法。把左括号看成 +$1$,右括号看成 -$1$,每个点表示当前的前缀和。
那么序列合法等价于,前缀和数组没有位置小于0,且最后一个数等于0。
对于这个题,在位置 $x$ 修改一个括号,就相当于区间 $[x, n]$ 加(减)2。
如果把一个左括号变成右括号,相当于区间 $-2$,那么只需要找当最左边的 $-1$位置,使它加 $2$ 就能使序列合法。
如果把一个右括号变成左括号,相当于区间 $+2$,那么找到第一个前缀和大于 $1$ 的位置,从他之后第一个 $1$ 变成 $-1$ 即可,这里我选择二分找那个位置。应该有1log的做法。
#include <bits/stdc++.h>
using namespace std; const int N = 3e5 + ;
int x[N], sum[N], n;
char s[N]; struct Seg {
#define lp p << 1
#define rp p << 1 | 1
int tree[N << ][];
void pushup(int p) {
tree[p][] = min(tree[lp][], tree[rp][]);
tree[p][] = min(tree[lp][], tree[rp][]);
}
void build(int p, int l, int r) {
if (l == r) {
if (l == || l == n) {
tree[p][] = tree[p][] = N;
return;
}
if (x[l] == ) tree[p][] = l, tree[p][] = N;
else tree[p][] = N, tree[p][] = l;
return;
}
int mid = l + r >> ;
build(lp, l, mid);
build(rp, mid + , r);
pushup(p);
}
void update(int p, int l, int r, int pos) {
if (l == r) {
swap(tree[p][], tree[p][]);
return;
}
int mid = l + r >> ;
if (pos <= mid) update(lp, l, mid, pos);
else update(rp, mid + , r, pos);
pushup(p);
}
int query(int p, int l, int r, int x, int y, int opt) {
if (x <= l && y >= r) return tree[p][opt];
int mid = l + r >> ;
int ans = N;
if (x <= mid) ans = min(ans, query(lp, l, mid, x, y, opt));
if (y > mid) ans = min(ans, query(rp, mid + , r, x, y, opt));
return ans;
}
} seg; struct Seg1 {
#define lp p << 1
#define rp p << 1 | 1
int tree[N << ], lazy[N << ];
void pushup(int p) {
tree[p] = min(tree[lp], tree[rp]);
}
void build(int p, int l, int r) {
if (l == r) {
tree[p] = sum[l];
return;
}
int mid = l + r >> ;
build(lp, l, mid);
build(rp, mid + , r);
pushup(p);
}
void tag(int p, int val) {
tree[p] += val;
lazy[p] += val;
}
void pushdown(int p) {
if (lazy[p]) {
tag(lp, lazy[p]);
tag(rp, lazy[p]);
lazy[p] = ;
}
}
void update(int p, int l, int r, int x, int y, int val) {
if (x <= l && y >= r) {
tree[p] += val;
lazy[p] += val;
return;
}
int mid = l + r >> ;
pushdown(p);
if (x <= mid) update(lp, l, mid, x, y, val);
if (y > mid) update(rp, mid + , r, x, y, val);
pushup(p);
}
int query(int p, int l, int r, int x, int y) {
if (x <= l && y >= r) return tree[p];
int mid = l + r >> ;
pushdown(p);
int ans = N;
if (x <= mid) ans = min(ans, query(lp, l, mid, x, y));
if (y > mid) ans = min(ans, query(rp, mid + , r, x, y));
return ans;
}
void print(int p, int l, int r){
if (l == r){
printf("%d ", tree[p]);
return;
}
int mid = l + r >> ;
pushdown(p);
print(lp, l, mid);
print(rp, mid + , r);
}
} seg1; int get(char ch) {
if (ch == '(') return ;
return -;
} int main() {
freopen("in.txt", "r", stdin);
int q;
scanf("%d%d", &n, &q);
scanf("%s", s + );
for (int i = ; i <= n; i++)
x[i] = get(s[i]), sum[i] = sum[i - ] + x[i];
seg.build(, , n);
seg1.build(, , n);
for (int u; q--; ) {
scanf("%d", &u);
if (u == || u == n) {
printf("%d\n", u);
continue;
}
seg.update(, , n, u);
if (x[u] == ) seg1.update(, , n, u, n, -);
else seg1.update(, , n, u, n, );
x[u] *= -;
int opt = (x[u] == ? : );
if (opt == ) {
int pos = seg.tree[][opt];
printf("%d\n", pos);
x[pos] *= -;
seg.update(, , n, pos);
seg1.update(, , n, pos, n, );
} else {
int l = , r = n;
int temp = ;
while (l <= r) {
int mid = l + r >> ;
if (seg1.query(, , n, mid, n) >= ) r = mid - , temp = mid;
else l = mid + ;
}
int pos = seg.query(, , n, temp, n, opt);
printf("%d\n", pos);
x[pos] *= -;
seg.update(, , n, pos);
seg1.update(, , n, pos, n, -);
}
}
return ;
}
还真有1log的
相当于查区间最后一个小于2的位置,那么先查右子树,如果右子树最小值小于2,就返回右,否则返回左。
#include <bits/stdc++.h>
using namespace std; const int N = 3e5 + ;
int x[N], sum[N], n;
char s[N]; struct Seg {
#define lp p << 1
#define rp p << 1 | 1
int tree[N << ][];
void pushup(int p) {
tree[p][] = min(tree[lp][], tree[rp][]);
tree[p][] = min(tree[lp][], tree[rp][]);
}
void build(int p, int l, int r) {
if (l == r) {
if (l == || l == n) {
tree[p][] = tree[p][] = N;
return;
}
if (x[l] == ) tree[p][] = l, tree[p][] = N;
else tree[p][] = N, tree[p][] = l;
return;
}
int mid = l + r >> ;
build(lp, l, mid);
build(rp, mid + , r);
pushup(p);
}
void update(int p, int l, int r, int pos) {
if (l == r) {
swap(tree[p][], tree[p][]);
return;
}
int mid = l + r >> ;
if (pos <= mid) update(lp, l, mid, pos);
else update(rp, mid + , r, pos);
pushup(p);
}
int query(int p, int l, int r, int x, int y, int opt) {
if (x <= l && y >= r) return tree[p][opt];
int mid = l + r >> ;
int ans = N;
if (x <= mid) ans = min(ans, query(lp, l, mid, x, y, opt));
if (y > mid) ans = min(ans, query(rp, mid + , r, x, y, opt));
return ans;
}
} seg; struct Seg1 {
#define lp p << 1
#define rp p << 1 | 1
int tree[N << ], lazy[N << ];
void pushup(int p) {
tree[p] = min(tree[lp], tree[rp]);
}
void build(int p, int l, int r) {
if (l == r) {
tree[p] = sum[l];
return;
}
int mid = l + r >> ;
build(lp, l, mid);
build(rp, mid + , r);
pushup(p);
}
void tag(int p, int val) {
tree[p] += val;
lazy[p] += val;
}
void pushdown(int p) {
if (lazy[p]) {
tag(lp, lazy[p]);
tag(rp, lazy[p]);
lazy[p] = ;
}
}
void update(int p, int l, int r, int x, int y, int val) {
if (x <= l && y >= r) {
tree[p] += val;
lazy[p] += val;
return;
}
int mid = l + r >> ;
pushdown(p);
if (x <= mid) update(lp, l, mid, x, y, val);
if (y > mid) update(rp, mid + , r, x, y, val);
pushup(p);
}
int query(int p, int l, int r) {
if (tree[p] > ) return l;
if (l == r) return l;
int mid = l + r >> ;
pushdown(p);
if (tree[rp] <= ) return query(rp, mid + , r);
return query(lp, l, mid);
}
void print(int p, int l, int r){
if (l == r){
printf("%d ", tree[p]);
return;
}
int mid = l + r >> ;
pushdown(p);
print(lp, l, mid);
print(rp, mid + , r);
}
} seg1; int get(char ch) {
if (ch == '(') return ;
return -;
} int main() {
freopen("in.txt", "r", stdin);
int q;
scanf("%d%d", &n, &q);
scanf("%s", s + );
for (int i = ; i <= n; i++)
x[i] = get(s[i]), sum[i] = sum[i - ] + x[i];
seg.build(, , n);
seg1.build(, , n);
for (int u; q--; ) {
scanf("%d", &u);
if (u == || u == n) {
printf("%d\n", u);
continue;
}
seg.update(, , n, u);
if (x[u] == ) seg1.update(, , n, u, n, -);
else seg1.update(, , n, u, n, );
x[u] *= -;
int opt = (x[u] == ? : );
if (opt == ) {
int pos = seg.tree[][opt];
printf("%d\n", pos);
x[pos] *= -;
seg.update(, , n, pos);
seg1.update(, , n, pos, n, );
} else {
int l = , r = n;
int temp = seg1.query(, , n) + ;
int pos = seg.query(, , n, temp, n, opt);
printf("%d\n", pos);
x[pos] *= -;
seg.update(, , n, pos);
seg1.update(, , n, pos, n, -);
}
}
return ;
}
2014-2015 ACM-ICPC, Asia Tokyo Regional Contest的更多相关文章
- hdu 5444 Elven Postman(二叉树)——2015 ACM/ICPC Asia Regional Changchun Online
Problem Description Elves are very peculiar creatures. As we all know, they can live for a very long ...
- (并查集)Travel -- hdu -- 5441(2015 ACM/ICPC Asia Regional Changchun Online )
http://acm.hdu.edu.cn/showproblem.php?pid=5441 Travel Time Limit: 1500/1000 MS (Java/Others) Memo ...
- (二叉树)Elven Postman -- HDU -- 54444(2015 ACM/ICPC Asia Regional Changchun Online)
http://acm.hdu.edu.cn/showproblem.php?pid=5444 Elven Postman Time Limit: 1500/1000 MS (Java/Others) ...
- 2015 ACM/ICPC Asia Regional Changchun Online HDU 5444 Elven Postman【二叉排序树的建树和遍历查找】
Elven Postman Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)T ...
- ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków
ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...
- 2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)
2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred) easy: ACE ...
- HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 Problem Description Given an undirected connecte ...
- 【二分】【最长上升子序列】HDU 5489 Removed Interval (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5489 题目大意: 一个N(N<=100000)个数的序列,要从中去掉相邻的L个数(去掉整个区间 ...
- 【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数 ...
随机推荐
- RICOH C4502彩色打印机取消双面打印功能
参考下面步骤:
- Java中调用存储过程
dao层: import java.util.Map; public interface AppGthdDao { public String gthd(Map map); } mapper层 < ...
- Phaser铁人三项
/** * 模拟铁人三项 */ public class PhaserTest { private static Random random = new Random(System.currentTi ...
- Java中List集合去除重复数据的六种方法
1. 循环list中的所有元素然后删除重复 public static List removeDuplicate(List list) { for ( int i = 0 ; i < list. ...
- Prometheus K8S部署
Prometheus K8S部署 部署方式:https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/prometheus ...
- 【linux】CentOS 6 使用cron定时任务,报错:Redirecting to /bin/systemctl restart crond.service
在centos7上,执行cron定时任务的相关命令,反馈如下: 定时任务执行,反馈是: Redirecting to /bin/systemctl restart crond.service 原因: ...
- RandomAccessFile vs FileChannel.open(path);
What kind of FileChannel object does the FileChannel.open(path) method return? Is it still random ac ...
- oracle查询哪些sp修改了某些表
select distinct s.owner ||'.'||s.name from dba_source swhere lower(s.TEXT) like '%insert%tb_flow_ins ...
- Entity Framework 学习系列(5) - EF 相关查询
目录 写在前面 一.使用Stopwatch 查询执行效率 二.简单查询 1.Linq写法: 2.Lambda表达式写法: 三.条件查询 1.Linq 写法 2.lambda 写法 四.聚合函数 1.L ...
- linux常用命令--开发调试篇
前言 Linux常用命令中有一些命令可以在开发或调试过程中起到很好的帮助作用,有些可以帮助了解或优化我们的程序,有些可以帮我们定位疑难问题.本文将简单介绍一下这些命令. 示例程序 我们用一个小程序,来 ...