A - Beginning

签到.

 #include <bits/stdc++.h>
using namespace std; int main()
{
int a[];
while (scanf("%d", a) != EOF)
{
for (int i = ; i < ; ++i) scanf("%d", a + i);
sort(a, a + );
int res = ;
for (int i = ; i < ; ++i) res = res * + a[i];
puts(res == ? "YES" : "NO");
}
return ;
}

B - KEYENCE String

 #include <bits/stdc++.h>
using namespace std; string s; string get(int pos)
{
string res = "";
for (int i = ; i <= pos; ++i) res += s[i];
int len = s.size();
for (int i = len - ( - pos - ); i < len; ++i) res += s[i];
return res;
} bool work()
{
for (int i = ; i < ; ++i)
{
string tmp = get(i);
if (tmp == "keyence") return ;
}
return ;
} int main()
{
while (cin >> s) puts(work() ? "YES" : "NO");
return ;
}

C - Exam and Wizard

Solved.

题意:

给出些个数字$A_i, 和 B_i$

要求构造$C_i 使得 C_i >= B_i 并且 \sum A_i = \sum C_i$

并且使得变动的数字个数最少

思路:

先弄出不足的部分,然后取差值最大的$A_i > B_i$ 的部分用堆维护,每次取最大的贡献出来补充

 #include <bits/stdc++.h>
using namespace std; #define N 100010
#define ll long long
int n, a[N], b[N]; int main()
{
while (scanf("%d", &n) != EOF)
{
for (int i = ; i <= n; ++i) scanf("%d", a + i);
for (int i = ; i <= n; ++i) scanf("%d", b + i);
ll need = ;
priority_queue <int, vector <int>, less <int> > pq;
int res = ;
for (int i = ; i <= n; ++i)
{
if (b[i] > a[i]) need += b[i] - a[i], ++res;
else if (b[i] < a[i]) pq.push(a[i] - b[i]);
}
while (!pq.empty() && need > )
{
int top = pq.top(); pq.pop();
need -= top; ++res;
}
if (need > ) puts("-1");
else printf("%d\n", res);
}
return ;
}

D - Double Landscape

Upsolved.

题意:

在$n * m的矩阵中填数,每行中最大的数为a_i, 每列中最大的数为b_i$

求填数方案

思路:

对于某个数$x$

如果它存在于多个$a_i 中 或者多个 b_i 中 $

那么无解

再考虑

它既存在于$a_i 也存在于 b_i 中

那么它的位置是确定的$

它只存在于某个$a_i或者某个b_i中$

那么它的方案数就是那一列或者那一行的$a_i$比它大的数的个数

它不存在于某个$a_i或者某个b_i中$

那么它的方案数是 $a_i > a_x 的个数 \cdot b_i > b_x的个数$

但是要减去比它大的数的个数

因为它能填的位置,比它大的数都能填,而且是子集关系

所以要让出一位

但是对于第二种情况不用考虑,因为第二种情况的那个数肯定是当前行或者当前列最大的

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 1100
const ll MOD = (ll)1e9 + ;
int n, m, a[N], b[N]; bool check()
{
for (int i = ; i <= n; ++i) for (int j = i + ; j <= n; ++j)
if (a[i] == a[j]) return false;
for (int i = ; i <= m; ++i) for (int j = i + ; j <= m; ++j)
if (b[i] == b[j]) return false;
return true;
} int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
for (int i = ; i <= n; ++i) scanf("%d", a + i);
for (int i = ; i <= m; ++i) scanf("%d", b + i);
sort(a + , a + + n);
sort(b + , b + + m);
if (!check()) puts("");
else
{
a[n + ] = n + ;
b[m + ] = m + ;
int l[] = {, };
ll res = ;
for (int i = ; i <= n * m; ++i)
{
while (l[] <= n && a[l[]] < i) ++l[];
while (l[] <= m && b[l[]] < i) ++l[];
ll d = ;
if (a[l[]] == i && b[l[]] == i)
d = ;
else if (a[l[]] == i && b[l[]] != i)
d = m - l[] + ;
else if (b[l[]] == i && a[l[]] != i)
d = n - l[] + ;
else
d = (m - l[] + ) * (n - l[] + ) - (n * m - i);
res = (res * d) % MOD;
}
printf("%lld\n", res);
}
}
return ;
}

E - Connecting Cities

Upsolved.

题意:

$n个城市,两个城市之间的边权是 |i - j| \cdot D + A_i + A_j$

求最小生成树

思路:

考虑将区间分成两部分

分别为$[l, mid] 和 [mid +1, r]$

考虑

左区间为$f[i] = a[i] - d * i$

右区间为$g[i] = a[i] + d * j$

令$f[0] 和 g[0] 为 Min(f[i]), g[0] 为 Min(g[i])$

那么我们将$(i, j_0), (i_0, j), (i_0, j_0) 连边$

我么考虑$(i, j)这种边一定比上面三种边的边权要大$

那么假设我们需要$(i, j)这种边来增加连通性,那么上面那三种边必定能满足$

所以分治建边 一共有$NlogN级别的边数 $

再做MST

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 200010
#define INFLL 0x3f3f3f3f3f3f3f3f
int n, m;
ll d, a[N];
struct Edge
{
int u, v; ll w;
Edge() {}
Edge(int u, int v, ll w) : u(u), v(v), w(w) {}
bool operator < (const Edge &other) const { return w < other.w; }
}edge[N * ]; void add(int l, int r)
{
if (l == r) return;
int mid = (l + r) >> ;
ll Min = INFLL; int pos = -;
for (int i = l; i <= mid; ++i)
{
ll f = a[i] - d * i;
if (f < Min)
{
Min = f;
pos = i;
}
}
for (int i = mid + ; i <= r; ++i)
edge[++m] = Edge(pos, i, a[pos] + a[i] + d * (i - pos));
Min = INFLL; pos = -;
for (int i = mid + ; i <= r; ++i)
{
ll f = a[i] + d * i;
if (f < Min)
{
Min = f;
pos = i;
}
}
for (int i = l; i <= mid; ++i)
edge[++m] = Edge(pos, i, a[pos] + a[i] + d * (pos - i));
add(l, mid);
add(mid + , r);
} int pre[N];
int find(int x) { return pre[x] == ? x : pre[x] = find(pre[x]); }
ll Kruskal()
{
memset(pre, , sizeof pre);
sort(edge + , edge + + m);
int cnt = ;
ll res = ;
for (int i = ; i <= m; ++i)
{
int u = edge[i].u, v = edge[i].v; ll w = edge[i].w;
int fu = find(u), fv = find(v);
if (fu == fv) continue;
pre[fu] = fv;
res += w;
++cnt;
if (cnt == n) return res;
}
return res;
} int main()
{
while (scanf("%d%lld", &n, &d) != EOF)
{
m = ;
for (int i = ; i <= n; ++i) scanf("%lld", a + i);
add(, n);
printf("%lld\n", Kruskal());
}
return ;
}

法二:

按$a_i大小排序$

每次对于当前$x, 在所有a_j <= a_x的 城市当中,对于在它两侧的,各选出一条最短边连边$

为什么这样贪心是对的

我们考虑假如存在一个城市$z\; a_z < a_i, 并且假设最短边的城市是y$

那么$(x, y) 和 (y, z) 都小于 (x, z)$

所以$(x, z)这条边一定不在MST中$

考虑这样证明

$dist(x, y) < dist(x, z) 非常显然$

考虑$dist(y, z) < dist(x, z)$

首先假设$z < y < x$

$dist(y, z) = a_y +a_z + d * (y - z)$

$dist(x, z) = a_x + a_z + d * (x - z)$

$dist(x, z) - dist(y, z) = a_x - a_y + d * (x - y) >= 0$

得证

再考虑$y < z < x$

$dist(x, y) = a_x + a_y + d * (x - y)$

$dist(z, y) = a_z + a_y + d * (z - y)$

$dist(x, y) - dist(z, y) = a_x - a_z + d * (x - z) >= 0$

又因为 $dist(x, y) <= dist(x, z)$

所以$dist(x, z) >= dist(x, y) >= dist(z, y)$

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 200010
#define INFLL 0x3f3f3f3f3f3f3f3f
int n, m;
ll d;
struct node
{
int id; ll v;
void scan(int id)
{
this->id = id;
scanf("%lld", &v);
}
bool operator < (const node &other) const { return v < other.v; }
}a[N];
struct Edge
{
int u, v; ll w;
Edge () {}
Edge (int u, int v, ll w) : u(u), v(v), w(w) {}
bool operator < (const Edge &other) const { return w < other.w; }
}edge[N << ]; struct SEG
{
struct node
{
ll Min; int pos;
node () {}
node (ll Min, int pos) : Min(Min), pos(pos) {}
void init() { Min = INFLL, pos = -; }
node operator + (const node &other) const
{
node res; res.init();
if (Min < other.Min)
{
res.Min = Min;
res.pos = pos;
}
else
{
res.Min = other.Min;
res.pos = other.pos;
}
return res;
}
}a[N << ], res;
void build(int id, int l, int r)
{
a[id].init();
if (l == r) return;
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
}
void update(int id, int l, int r, int pos, ll v)
{
if (l == r)
{
a[id] = node(v, pos);
return;
}
int mid = (l + r) >> ;
if (pos <= mid) update(id << , l, mid, pos, v);
else update(id << | , mid + , r, pos, v);
a[id] = a[id << ] + a[id << | ];
}
void query(int id, int l, int r, int ql, int qr)
{
if (qr < ql) return;
if (l >= ql && r <= qr)
{
res = res + a[id];
return;
}
int mid = (l + r) >> ;
if (ql <= mid) query(id << , l, mid, ql, qr);
if (qr > mid) query(id << | , mid + , r, ql, qr);
}
}seg[]; int pre[N];
int find(int x) { return pre[x] == ? x : pre[x] = find(pre[x]); }
ll Kruskal()
{
memset(pre, , sizeof pre);
sort(edge + , edge + + m);
int cnt = ;
ll res = ;
for (int i = ; i <= m; ++i)
{
int u = edge[i].u, v = edge[i].v; ll w = edge[i].w;
int fu = find(u), fv = find(v);
if (fu == fv) continue;
pre[fu] = fv;
++cnt;
res += w;
if (cnt == n) return res;
}
return res;
} int main()
{
while (scanf("%d%lld", &n, &d) != EOF)
{
m = ;
for (int i = ; i <= n; ++i) a[i].scan(i);
for (int i = ; i < ; ++i) seg[i].build(, , n);
sort(a + , a + + n);
for (int i = ; i <= n; ++i)
{
int u = a[i].id, v;
for (int j = ; j < ; ++j)
seg[j].res.init();
seg[].query(, , n, , u - );
seg[].query(, , n, u + , n);
for (int j = ; j < ; ++j) if (seg[j].res.pos != -)
{
v = seg[j].res.pos;
edge[++m] = Edge(u, v, a[i].v + 1ll * (j ? - : ) * d * u + seg[j].res.Min);
}
seg[].update(, , n, u, a[i].v - d * u);
seg[].update(, , n, u, a[i].v + d * u);
}
printf("%lld\n", Kruskal());
}
return ;
}

KEYENCE Programming Contest 2019 Solution的更多相关文章

  1. KEYENCE Programming Contest 2019 自闭记

    A:签到. #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> ...

  2. 【AtCoder】KEYENCE Programming Contest 2019

    A - Beginning 这个年份恐怕需要+2 #include <bits/stdc++.h> #define fi first #define se second #define p ...

  3. AISing Programming Contest 2019 Solution

    A - Bulletin Board 签到. #include <bits/stdc++.h> using namespace std; int main() { int n, h, w; ...

  4. [AtCoder] NIKKEI Programming Contest 2019 (暂缺F)

    [AtCoder] NIKKEI Programming Contest 2019   本来看见这一场的排名的画风比较正常就来补一下题,但是完全没有发现后两题的AC人数远少于我补的上一份AtCoder ...

  5. [AtCoder] Yahoo Programming Contest 2019

    [AtCoder] Yahoo Programming Contest 2019   很遗憾错过了一场 AtCoder .听说这场是涨分场呢,于是特意来补一下题. A - Anti-Adjacency ...

  6. Yahoo Programming Contest 2019.E.Odd Subrectangles(思路 线性基)

    题目链接 \(Description\) 给定一个\(n\times m\)的\(01\)矩阵.求任意选出\(r\)行.\(c\)列(共\(2^{n+m}\)种方案),使得这\(r\)行\(c\)列的 ...

  7. ACM ICPC, Amman Collegiate Programming Contest (2018) Solution

    Solution A:Careful Thief 题意:给出n个区间,每个区间的每个位置的权值都是v,然后找长度为k的区间,使得这个区间的所有位置的权值加起来最大,输出最大权值, 所有区间不重叠 思路 ...

  8. AtCoder NIKKEI Programming Contest 2019 C. Different Strokes (贪心)

    题目链接:https://nikkei2019-qual.contest.atcoder.jp/tasks/nikkei2019_qual_C 题意:给出 n 种食物,Takahashi 吃下获得 a ...

  9. 2020.3.14--训练联盟周赛 Preliminaries for Benelux Algorithm Programming Contest 2019

    1.A题 题意:给定第一行的值表示m列的最大值,第m行的值表示n行的最大值,问是否会行列冲突 思路:挺简单的,不过我在一开始理解题意上用了些时间,按我的理解是输入两组数组,找出每组最大数,若相等则输出 ...

随机推荐

  1. GIS-002-gdal2srtmtiles使用注意事项

    本次安装和配置过程重点参考了: 1.http://blog.csdn.net/wjkwjk/article/details/52560236 2.http://blog.csdn.net/wjkwjk ...

  2. nohub和重定向文件

    1.如果使用远程连接的Linux的方式并想后台运行执行如下命令: 格式:nohup <程序名> & 比如:nohup /usr/local/collection/bin/start ...

  3. 什么原因接触接触impala的

    最近一个项目,关于大数据的改造项目,底层选择Impala还是sparkSQL呢? 最后选择Impala.这样就开启了我的Impala学习之旅.我大部分负责Imapa接口开发工作. 我是控制不住的想整个 ...

  4. Qt监控后台服务运行状态

    mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QMa ...

  5. Linux同步网络时间

    1.date '+%Y%M%D' 按照格式显示当前日期,结果如下: [root@LAMP ~]# date "+%Y-%m-%d %H:%M:%S" -- :: 2.date -s ...

  6. Putty的安装和使用

     Putty是最简单易用的SSH工具,详细介绍其安装和使用 直接在百度里搜索Putty,可以找到百度软件中心,或者官方网站: PuTTY Download Page.  进入官方网站,直接可执行文件装 ...

  7. 安装memcacheq

    1.下载memcacheq包    下载地址:http://code.google.com/p/memcacheq/downloads/list    解压包:# tar -zxvf memcache ...

  8. 《C++ Primer Plus》第7章 函数——C++的编程模块 学习笔记

    函数是C++的编程模块.要使用函数,必须提供定义和原型,并调用该函数.函数定义是实现函数功能的代码:函数原型描述了函数的接口:传递给函数的值的书目和种类以及函数的返回类型.函数调用使得程序将参数传递给 ...

  9. JDK1.8在LINUX下安装步骤

    JDK1.8在LINUX下安装步骤: 在/usr/lib/目录下新建jvm文件夹,如果已有jvm文件夹,则将之前的JDK版本删除,即在jvm目录下执行命令:rm –rf * 将JDK文件jdk-8u4 ...

  10. 【java】将List中的实体按照某个字段进行分组的算法

    如何将List中存放的实体按照某个字段进行分组呢?来看看下面的例子,假如实体中有个字段叫批次号,我们将具有相同批次号的实体放在一起,那么怎么实现呢?看下面的代码: 可以定义个Map,Map的key用于 ...