文章目录
A - XXXXX [思维]
Time Limit Per Test | Memory Limit Per Test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
题意
有 n n n 个数的数组 a [ ] a[] a[],要使数组的总和 % k ! = 0 \% k != 0 %k!=0
可以选择删去开始的连续几个数或者删去末尾的连续几个数
问这个数组满足条件的最长长度,不存在则输出 − 1 -1 −1
分析
只要找到头尾最近的一个 % k ! = 0 \% k != 0 %k!=0 的数,然后扣掉这一整段的长度
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
int a[maxn];
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n, x, ans = -1, sum = 0;
scanf("%d%d", &n, &x);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
a[i] %= x, sum += a[i];
if(a[i]) ans = 0;
}
if(ans == -1) {
puts("-1");
}else if(sum % x) {
printf("%d\n", n);
}else{
int id = 1, id2 = n;
while(id <= n && a[id] == 0) id += 1;
while(id2 > id && a[id2] == 0) id2 -= 1;
printf("%d\n", max(n - id, id2 - 1));
}
}
return 0;
}
B - Sign Flipping [思维]
Time Limit Per Test | Memory Limit Per Test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
题意
有 n n n 个数的数组 a [ ] a[] a[],可以任意次 选择删去任意位置的数
最大化 ∣ a [ i + 1 ] − a [ i ] ∣ | a[i + 1] - a[i] | ∣a[i+1]−a[i]∣ 且使得数组长度尽可能小,
则删去后的数组应为怎样的。
分析
在一段连续不递减的区间中,删除【除头尾外的元素】后,得到的结果是不变的
同理在一段连续不递减的区间中,删除【除头尾外的元素】后,得到的结果是也不变的
因此最后保留的就是山峰式的数组 【矮 高 矮 高 …】,【高 矮 高 矮…】
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
int a[maxn];
vector<int> v;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n; v.clear();
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
if(n == 2) {
printf("2\n%d %d\n", a[1], a[2]);
continue;
}
int m = 0; v.push_back(a[1]);
for(int i = 2; i < n; ++i) {
if(a[i] <= v[m] && a[i] <= a[i + 1])
v.push_back(a[i]), m += 1;
else if(a[i] >= v[m] && a[i] >= a[i + 1])
v.push_back(a[i]), m += 1;
}
v.push_back(a[n]), m += 1;
printf("%d\n", m + 1);
for(int i = 0; i <= m; ++i)
printf("%d%c", v[i], i == m ? '\n' : ' ');
}
return 0;
}
C - Ehab and Prefix MEXs [构造][并查集]
Time Limit Per Test | Memory Limit Per Test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
题意
给一个数组
a
[
]
a[]
a[],有
n
n
n 个数,构造一个数组
b
[
]
b[]
b[]
要满足
a
[
i
]
=
M
E
X
(
b
[
1
]
,
b
[
2
]
,
.
.
.
b
[
i
]
)
a[i] = MEX(b[1], b[2], ... b[i])
a[i]=MEX(b[1],b[2],...b[i])
其中
M
E
X
MEX
MEX 表示 数组中未出现过的最小的数(从0开始)
若找不到这样的数组
b
b
b,则输出 -1
保证数组
a
[
i
+
1
]
>
a
[
i
]
&
&
0
≤
a
[
i
]
≤
i
a[i + 1] > a[i] \&\& 0 \leq a[i] \leq i
a[i+1]>a[i]&&0≤a[i]≤i
分析
其实不管怎样都是可以构造出来的,因为保证了
a
[
i
+
1
]
>
a
[
i
]
&
&
0
≤
a
[
i
]
≤
i
a[i + 1] > a[i] \&\& 0 \leq a[i] \leq i
a[i+1]>a[i]&&0≤a[i]≤i
我的跟标准题解的做法不太一样。。
从后往前遍历
如果
a
[
i
]
>
a
[
i
−
1
]
a[i] > a[i - 1]
a[i]>a[i−1],则令
b
[
i
]
=
a
[
i
−
1
]
b[i] = a[i - 1]
b[i]=a[i−1](
a
[
i
−
1
]
a[i-1]
a[i−1]就是前
i
−
1
i-1
i−1个数中最大的)
否则只有
a
[
i
]
=
a
[
i
−
1
]
a[i] = a[i - 1]
a[i]=a[i−1] 的情况,则令
b
[
i
]
=
a
[
i
]
+
1
b[i] = a[i] + 1
b[i]=a[i]+1
除此之外利用并查集查找可以选择的最小的数。
连接
a
[
i
]
,
a
[
i
]
+
1
a[i], a[i] + 1
a[i],a[i]+1 是因为这个位置的
M
E
X
=
a
[
i
]
MEX = a[i]
MEX=a[i] 的话意味着前面的数都不可以等于
a
[
i
]
a[i]
a[i]
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int inf = 0x3f3f3f3f;
int b[maxn];
int a[maxn];
int ma[maxn];
int pre[maxn * 10];
int _find(int x) {
return x == pre[x] ? x : pre[x] = _find(pre[x]);
}
void _union(int x, int y) {
x = _find(x), y = _find(y);
if(x < y) pre[x] = y;
else pre[y] = x;
}
int main() {
int n;
scanf("%d", &n);
for(int i = 0; i < maxn * 10; ++i) pre[i] = i;
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
ma[i] = max(ma[i - 1], a[i]);
}
int x = 0;
for(int i = n; i > 0; --i) {
if(a[i] > ma[i - 1])
b[i] = ma[i - 1];
else
b[i] = a[i] + 1;
b[i] = _find(b[i]);
_union(b[i], b[i] + 1);
_union(a[i], a[i] + 1);
}
for(int i = 1; i <= n; ++i)
printf("%d%c", b[i], i == n ? '\n' : ' ') ;
return 0;
}
D - Ehab’s Last Corollary [dfs环长度]
Time Limit Per Test | Memory Limit Per Test | input | output |
---|---|---|---|
1 seconds | 256 megabytes | standard input | standard output |
题意
给一个无向连通图,保证没有自环以及重边
输出可以有两种方式:
第一:输出独立点集,包含有 ⌈ k 2 ⌉ \left \lceil {\frac{k}{2}} \right \rceil ⌈2k⌉ 个点,独立集是一组顶点,它们之间没有一条边连接。
第二:输出一个简单环,长度最大为 k k k,简单循环是一个不包含任何两次顶点的循环。
分析
如果环的长度都大于 k k k,则必定存在 ≥ ⌈ k 2 ⌉ \ge \left \lceil {\frac{k}{2}} \right \rceil ≥⌈2k⌉ 个相互独立的点
只要用 d f s dfs dfs 找最小环,如果存在这样的环则直接输出
为了输出不存在的情况,用 v i s [ i ] vis[i] vis[i] 标记选择到独立集的点
如果这个点选择了,则相邻的其他所有点都要标记为不可选择
最后再输出选择的点
Code
#include <bits/stdc++.h>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) < (b) ? (b) : (a))
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int inf = 2e9 + 1;
const int maxn = 2e5 + 5;
vector<int> ed[maxn << 1];
bool vis[maxn]; // 独立点集
int res[maxn]; // 每个深度的点
int dep[maxn]; // 深度
int n, m, k;
void dfs(int u, int fa, int deep) {
res[deep] = u, dep[u] = deep;
for(auto v : ed[u]) {
if(v == fa) continue;
if(dep[v] && dep[u] - dep[v] + 1 > 0 && dep[u] - dep[v] + 1 <= k) {
printf("2\n%d\n", dep[u] - dep[v] + 1);
for(int i = dep[v]; i <= dep[u]; ++i)
printf("%d%c", res[i], i == dep[u] ? '\n' : ' ');
exit(0);
}else if(dep[v] == 0) {
dfs(v, u, deep + 1);
}
}
if(vis[u]) {
for(auto v : ed[u]) vis[v] = false;
}
}
int main() {
int u, v;
memset(dep, 0, sizeof(dep));
memset(vis, true, sizeof(vis));
for(int i = 1; i <= n; ++i) ed[i].clear();
scanf("%d%d%d", &n, &m, &k);
while(m--) {
scanf("%d%d", &u, &v);
ed[u].push_back(v), ed[v].push_back(u);
}
dfs(1, 1, 1);
puts("1"); k = k % 2 + k / 2;
for(int i = 1; k && i <= n; ++i) {
if(vis[i] && k--)
printf("%d%c", i, k ? ' ' : '\n');
}
return 0;
}