A. Swap Adjacent Elements
题目大意
在长度为 n n 的草坪上,有个水龙头,第 i i 个水龙头位置为,水龙头的水在打开后第 j j 秒会对[x-(j-1), x+(j-1)]内的所有草坪洒水。现在同时打开所有水龙头,求最短多少秒时所有草坪都能被洒到水?
思路 - 模拟
相邻两个水龙头之间的草坪全部能被洒水需要秒,左端点处能在 x1 x 1 内将左边的草坪洒上水,又端点出能在 n−xk+1 n − x k + 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
题目大意
有 n n 个人在排队,第个人在 li l i 时到达队尾,若在 ri r i 时还未在队首,则必须空手离开;队首的人会获得茶,然后在下一秒离开;求每个人端着茶的时间,不存在则为 0 0 。
思路 - 模拟
模拟每个人入队后的情况:
①若当前可获得时间,则能在
max(l,time)
m
a
x
(
l
,
t
i
m
e
)
获得茶,下一次可获得茶的时间为
time=max(l,time)+1
t
i
m
e
=
m
a
x
(
l
,
t
i
m
e
)
+
1
;
②如当前可获得时间
time>r
t
i
m
e
>
r
,则不能获得茶而离开,结果为
0
0
。
代码
#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
题目大意
有一个长度为的数组,数组内为 1 n 1 n 的一个排列,现有一个操作:交换 xi x i 和 xi+1 x i + 1 (无次数限制),在给定长度为 n−1 n − 1 的 01串 01 串 , 0 0 表示数组中相同下标的数不能进行这样的操作;表示数组中相同下标的数能进行这样的操作。求当前数组能否变成一个递增的数组?
思路 - 模拟
很容易就能发现若存在连续为 1 1 的区间,则 [l,r+1] [ l , r + 1 ] 内的数能交换到该区间内的任意以一个位置,所以以 0 0 将数组划分为多个区间,若每个区间内的数都是其区间内的一个下标,则最终能变成一个递增的数组。
代码
#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[n] = '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?
题目大意
给定个的顶点的无向图,以及图中不存在的边,求该无向图的联通分量的个数及每个联通分量的大小?
思路 - dfs
很容易就能想到 dfs d f s 求联通分量,但是由于该无向图是密集图,不能通过遍历边的方式进行搜索,只能通过遍历点的方式进行搜索。所以需要维护未使用的点集(我使用链表实现,并通过并查集思想快速获得下一个未使用的顶点),每次进入 dfs d f s 时,对于当前顶点 u u ,遍历未使用的点,如果 u u 到存在边,则移除点 v v ,递归即可。
代码
#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
题目大意
给定长度为的数组,有两个操作:
①将
[l,r]
[
l
,
r
]
内的所有数变成其因子的个数
②求
[l,r]
[
l
,
r
]
内所有数的和
思路 - 线段树
看到区间更新和查询,很容易就能想到线段树。
但是要注意更新的特殊性,就能发觉每个数减少的很快,最多
6
6
次之后就不再变化,所以在更新前,要判断当前线段内的数是否存在可以继续更新的值(只有不能进行更新)。而这样对每个点的更新操作最多只有
6
6
次,所以可以放心更新。
对于每个点维护两个值:表示线段内的最大值,用于更新剪枝; sum s u m 表示线段内所有数的和,用于查询结果。
代码
#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));
}
}
}
}