您的位置:首页 > 其它

Educational Codeforces Round 37 [Codeforces920]

2018-02-04 23:26 309 查看
题目链接

官方题解

A. Swap Adjacent Elements

题目大意

在长度为nn的草坪上,有kk个水龙头,第ii个水龙头位置为xixi,水龙头的水在打开后第jj秒会对[x-(j-1), x+(j-1)]内的所有草坪洒水。现在同时打开所有水龙头,求最短多少秒时所有草坪都能被洒到水?

思路 - 模拟

相邻两个水龙头之间的草坪全部能被洒水需要cur−last2+1cur−last2+1秒,左端点处能在x1x1内将左边的草坪洒上水,又端点出能在n−xk+1n−xk+1内将右边的草坪洒上水,则答案为所有值中的最大值。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 203;

int n, k, ans, last, cur;

int main() {
int T;
scanf("%d", &T);
while(T-- > 0) {
scanf("%d%d", &n, &k);
scanf("%d", &last);
ans = last;
while(--k > 0) {
scanf("%d", &cur);
ans = max(ans, ((cur - last) >> 1) + 1);
last = cur;
}
ans = max(ans, n - last + 1);
printf("%d\n", ans);
}
}


B. Tea Queue

题目大意

有nn个人在排队,第ii个人在lili时到达队尾,若在riri时还未在队首,则必须空手离开;队首的人会获得茶,然后在下一秒离开;求每个人端着茶的时间,不存在则为00。

思路 - 模拟

模拟每个人入队后的情况:

①若当前可获得时间time<=rtime<=r,则能在max(l,time)max(l,time)获得茶,下一次可获得茶的时间为time=max(l,time)+1time=max(l,time)+1;

②如当前可获得时间time>rtime>r,则不能获得茶而离开,结果为00。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 1003;

int n, time;
int l, r, ans[MAXN];

int main() {
int T;
scanf("%d", &T);
while(T-- > 0) {
scanf("%d", &n);
time = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &l, &r);
if(r >= time) {
ans[i] = max(l, time) ;
time = ans[i] + 1;

}
else {
ans[i] = 0;
}
}
for(int i = 1; i <= n; ++i) {
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
}
}


C. Swap Adjacent Elements

题目大意

有一个长度为nn的数组,数组内为1 n1 n的一个排列,现有一个操作:交换xixi和xi+1xi+1(无次数限制),在给定长度为n−1n−1的01串01串,00表示数组中相同下标的数不能进行这样的操作;11表示数组中相同下标的数能进行这样的操作。求当前数组能否变成一个递增的数组?

思路 - 模拟

很容易就能发现若存在连续为11的区间[l,r][l,r],则[l,r+1][l,r+1]内的数能交换到该区间内的任意以一个位置,所以以00将数组划分为多个区间,若每个区间内的数都是其区间内的一个下标,则最终能变成一个递增的数组。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 200003;

int n, a[MAXN], last;
char s[MAXN];
int nxt[MAXN];
bool border;

bool judge() {
s
= '0';
for(int i = n; i >= 1; --i) {
if(s[i] == '0') {
nxt[i] = i;
}
else {
nxt[i] = nxt[i + 1];
}
}
border = false;
for(int i = 1; i <= n; ++i) {
if(a[i] > nxt[i]) {
return false;
}
if(s[i] == '0') {
if(!border && a[i] != i) {
return false;
}
border = false;
}
else {
if(a[i] == nxt[i]) {
border = true;
}
}
}
return true;
}

int main() {
while(1 == scanf("%d", &n)) {
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
scanf("%s", s + 1);
printf("%s\n", judge() ? "YES" : "NO");
}
}


E. Connected Components?

题目大意

给定nn个的顶点的无向图,以及图中不存在的边,求该无向图的联通分量的个数及每个联通分量的大小?

思路 - dfs

很容易就能想到dfsdfs求联通分量,但是由于该无向图是密集图,不能通过遍历边的方式进行搜索,只能通过遍历点的方式进行搜索。所以需要维护未使用的点集(我使用链表实现,并通过并查集思想快速获得下一个未使用的顶点),每次进入dfsdfs时,对于当前顶点uu,遍历未使用的点vv,如果uu到vv存在边,则移除点vv,递归即可。

代码

#include <cstdio>
#include <cstring>
#include <set>
#include <algorithm>

using namespace std;

const int MAXN = 200003;

int n, m, cnt;
int ans[MAXN];
set<int> edge[MAXN];
int nxt[MAXN];
bool vis[MAXN];

int getNxt(int cur) {
if(vis[nxt[cur]]) {
nxt[cur] = getNxt(nxt[cur]);
}
return nxt[cur];
}

int dfs(int u) {
int res = 0, v;
for(v = getNxt(0); v <= n; v = getNxt(v)) {
if(edge[u].find(v) == edge[u].end()) {
vis[v] = true;
res += dfs(v) + 1;
}
}
return res;
}

int main() {
int u, v;
while(2 == scanf("%d%d", &n, &m)) {
vis[n + 1] = false;
nxt[0] = 1;
for(int i = 1; i <= n; ++i) {
edge[i].clear();
vis[i] = false;
nxt[i] = i + 1;
}
while(m-- > 0) {
scanf("%d%d", &u, &v);
edge[u].insert(v);
edge[v].insert(u);
}
cnt = 0;
for(v = getNxt(0); v <= n; v = getNxt(v)) {
vis[v] = true;
ans[cnt++] = dfs(v) + 1;
}
sort(ans, ans + cnt);
printf("%d\n", cnt);
for(int i = 0; i < cnt; ++i) {
printf("%d%c", ans[i], i == cnt - 1 ? '\n' : ' ');
}
}
}


F. SUM and REPLACE

题目大意

给定长度为nn的数组,有两个操作:

①将[l,r][l,r]内的所有数变成其因子的个数

②求[l,r][l,r]内所有数的和

思路 - 线段树

看到区间更新和查询,很容易就能想到线段树。

但是要注意更新的特殊性,就能发觉每个数减少的很快,最多66次之后就不再变化,所以在更新前,要判断当前线段内的数是否存在可以继续更新的值(只有1和21和2不能进行更新)。而这样对每个点的更新操作最多只有66次,所以可以放心更新。

对于每个点维护两个值:mxmx表示线段内的最大值,用于更新剪枝;sumsum表示线段内所有数的和,用于查询结果。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

#define lson (i << 1)
#define rson ((i << 1) | 1)

using namespace std;

const int MAXN = 300003;
const int MAX_VALUE = 1000003;

int d[MAX_VALUE], L, R;

struct Node {
int l, r;
int mx;
long long sum;
}tr[MAXN << 2];

void build(int i, int l, int r) {
tr[i].l = l;
tr[i].r = r;
if(l == r) {
scanf("%d", &tr[i].mx);
tr[i].sum = tr[i].mx;
return ;
}

int mid = (l + r) >> 1;
build(lson, l , mid);
build(rson, mid + 1, r);
tr[i].mx = max(tr[lson].mx, tr[rson].mx);
tr[i].sum = tr[lson].sum + tr[rson].sum;
}

void update(int i) {
if(tr[i].l == tr[i].r) {
tr[i].sum = tr[i].mx = d[tr[i].mx];
return ;
}

if(L <= tr[lson].r && tr[lson].mx > 2) {
update(lson);
}
if(tr[rson].l <= R && tr[rson].mx > 2) {
update(rson);
}
tr[i].mx = max(tr[lson].mx, tr[rson].mx);
tr[i].sum = tr[lson].sum + tr[rson].sum;
}

long long query(int i) {
if(L <= tr[i].l && tr[i].r <= R) {
return tr[i].sum;
}

long long ans = 0;
if(L <= tr[lson].r) {
ans += query(lson);
}
if(tr[rson].l <= R) {
ans += query(rson);
}
return ans;
}

void init() {
memset(d, 0, sizeof(d));
for(int i = 1; i < MAX_VALUE; ++i) {
for(int j = i; j < MAX_VALUE; j += i) {
++d[j];
}
}
}

int n, m;
int type;

int main() {
init();
while(2 == scanf("%d%d", &n, &m)) {
build(1, 1, n);
while(m-- > 0) {
scanf("%d%d%d", &type, &L, &R);
if(type == 1) {
update(1);
}
else {
printf("%I64d\n", query(1));
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: