题解:ABC395(A-E)
PS:由于作者后60分钟选择先做G题,所以他F和G都没做出来()
A - Strictly Increasing?
问题陈述
给你一个正整数 \(N\) 和一个长度为 \(N\) 的正整数序列 \(A = (A_1,A_2,\dots,A_N)\) 。
请判断 \(A\) 是否严格递增,即 \(A_i < A_{i+1}\) 是否对 \(1 \leq i < N\) 的每个整数 \(i\) 都成立。
思路
在线性搜索时判断当前元素与上一个元素的大小关系,如果为小于或等于则直接输出NO。
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 110;
int a[maxn];
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
int n;cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i];
if(a[i] <= a[i-1]){
cout<<"No";
return 0;
}
}
cout<<"Yes";
return 0;
}
B - Make Target
问题陈述
概述**:创建一个 \(N \times N\) 模式,如下所示。
给你一个正整数 \(N\) 。
考虑一个 \(N \times N\) 网格。让 \((i,j)\) 表示从上往下第 \(i\) 行,从左往上第 \(j\) 列的单元格。最初,没有单元格被着色。
然后,依次对 \(i = 1,2,\dots,N\) 执行以下操作:
- 让 \(j = N + 1 - i\) .
- 如果是 \(i \leq j\) ,则在左上角单元格为 \((i,i)\) 、右下角单元格为 \((j,j)\) 的矩形区域填充黑色(如果 \(i\) 为奇数),如果 \(i\) 为偶数,则填充白色。如果某些单元格已经着色,则覆盖它们的颜色。
- 如果是 \(i > j\) ,则不做任何操作。
经过所有这些操作后,可以证明没有未着色的单元格。确定每个单元格的最终颜色。
思路
小模拟,题面说什么跟着做什么就好,N非常小,不用考虑时间以及空间上的问题。
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 55;
int n;
char c[maxn][maxn];
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n;
for(int i = 1;i <= n;i++){
int j = n + 1 -i;
if(i <= j){
if(i & 1){
for(int a = i;a <= j;a++){
for(int b = i;b <= j;b++){
c[a][b] = '#';
}
}
}else{
for(int a = i;a <= j;a++){
for(int b = i;b <= j;b++){
c[a][b] = '.';
}
}
}
}
}
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
cout<<c[i][j];
}
cout<<'\n';
}
return 0;
}
C - Shortest Duplicate Subarray
问题陈述
给你一个正整数 \(N\) 和一个长度为 \(N\) 的整数序列 \(A = (A_1,A_2,\dots,A_N)\) 。
请判断 \(A\) 中是否存在一个非空(连续)子数组,它有一个重复值,多次出现在 \(A\) 中。如果存在这样的子数组,求最短的子数组的长度。
思路
开桶判断有没有被记录过,如果记录过则把上一次记录的位置与当前位置之间的距离与ans进行判断,如果ans没有被更改过则输出-1。
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
#define inf 0x3f3f3f3f
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 1e6+10;
struct node{
bool vis;
int pos;
}a[maxn];
int n,x,ans = inf;
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n;
for(int i = 1;i <= n;i++)
{
cin>>x;
if(a[x].vis){
ans = min(ans,i - a[x].pos + 1);
}
a[x].vis = 1;
a[x].pos = i;
}
if(ans == inf){
cout<<-1;
return 0;
}
cout<<ans;
return 0;
}
D - Pigeon Swap
问题陈述
有 \(N\) 只标有 \(1, 2, \ldots, N\) 的鸽子和 \(N\) 个标有 \(1, 2, \ldots, N\) 的鸽巢。
最初,鸽子 \(i\) \((1 \leq i \leq N)\) 在巢 \(i\) 中。
您将对这些鸽子进行 \(Q\) 次操作。
操作有三种:
- 类型 \(1\) :给你整数 \(a\) 和 \(b\) 。 \((1 \leq a \leq N, 1 \leq b \leq N)\) .将鸽子 \(a\) 从当前巢中取出,移到巢 \(b\) 中。
- 输入 \(2\) :给你整数 \(a\) 和 \(b\) 。 \((1 \leq a < b \leq N)\) .将巢 \(a\) 中的所有鸽子移动到巢 \(b\) ,并将巢 \(b\) 中的所有鸽子移动到巢 \(a\) 。这两次移动同时进行。
- 输入 \(3\) :给你一个整数 \(a\) \((1 \leq a \leq N)\) 。鸽子 \(a\) 报告它目前所在巢的标签。
按照给出的操作顺序打印每个 \(3\) 类型操作的结果。
思路
貌似以前见到过,记录分别记录鸽子的位置以及鸽巢编号,模拟出每次操作的效果即可。
#include<bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int maxn = 1000010;
int n, m;
int p[maxn], q[maxn], pos[maxn];
int main(){
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
cin>>n>>m;
for (int i = 1; i <= n; ++i)pos[i] = p[i] = q[i] = i;
int t, a, b;
while (m--)
{
cin>>t>>a;
if (t == 1) {
cin>>b;
pos[a] = q[b];
}else if (t == 2) {
cin>>b;
swap(q[a], q[b]);
swap(p[q[a]], p[q[b]]);
} else {
cout<<p[pos[a]]<<'\n';
}
}
return 0;
}
E - Flip Edge
问题陈述
问题陈述
给你一个有向图,图中有 \(N\) 个顶点和 \(M\) 条边。 \(i\) -th 边 \((1 \leq i \leq M)\) 是一条从顶点 \(u _ i\) 到顶点 \(v _ i\) 的有向边。
最初,您位于顶点 \(1\) 。您要重复以下操作直到到达顶点 \(N\) :
- 执行以下两个操作之一:
- 从当前顶点沿一条有向边移动。这样做的代价是 \(1\) 。更精确地说,如果你在顶点 \(v\) ,选择一个顶点 \(u\) ,使得有一条从 \(v\) 到 \(u\) 的有向边,然后移动到顶点 \(u\) 。
- 逆转所有边的方向。这样做的代价是 \(X\) 。更确切地说,如果且仅如果在此操作之前有一条从 \(v\) 到 \(u\) 的有向边,那么在此操作之后有一条从 \(u\) 到 \(v\) 的有向边。
可以保证,对于给定的图,重复这些操作可以从顶点 \(1\) 到达顶点 \(N\) 。
求到达顶点 \(N\) 所需的最小总成本。
思路
跑dijstra的时候分别处理正向边和反向边,把得到的成本都放入优先队列内即可。
#include <bits/stdc++.h>
#define debug(a) cout << #a << "=" << a << '\n';
#define il inline
using namespace std;
using ll = long long;
using ull = unsigned long long;
typedef pair<ll, int> node;
const int maxn = 2e5 + 10;
int n, m, c;
ll a[maxn][2];
priority_queue<node, vector<node>, greater<node>> q;
struct E {
int to, next;
} Edge[maxn], Rdge[maxn];
int tot, Head[maxn], Rtot, RHead[maxn];
inline void add1(int u, int v) {
Edge[tot].to = v;
Edge[tot].next = Head[u];
Head[u] = tot++;
}
inline void add2(int u, int v) {
Rdge[Rtot].to = v;
Rdge[Rtot].next = RHead[u];
RHead[u] = Rtot++;
}
int main() {
// freopen("test.in","r",stdin);
// freopen("test.out","w",stdout);
ios::sync_with_stdio(0), cout.tie(0), cin.tie(0);
cin >> n >> m >> c;
memset(Head, -1, sizeof(Head));
memset(RHead, -1, sizeof(RHead));
memset(a, 0x3f, sizeof(a));
for (int i = 0, x, y; i < m; ++i) {
cin >> x >> y;
add1(x, y);add2(y, x);
}
a[1][0] = 0ll;
q.emplace(0ll, 2 * 1);
while (!q.empty()) {
auto [d, u] = q.top();
q.pop();
bool f = u & 1;
u>>=1;
if (a[u][f] != d)continue;
if (u == n){cout<<d;return 0;}
for (int i = Head[u];~i;i = Edge[i].next) {
int v = Edge[i].to;
ll w = d + 1 + (f ? c : 0);
if (w < a[v][0]) {
a[v][0] = w;
q.emplace(w, 2 * v);
}
}
for (int i = RHead[u];~i;i = Rdge[i].next) {
int v = Rdge[i].to;
ll w = d + 1 + (f ? 0 : c);
if (w < a[v][1]) {
a[v][1] = w;
q.emplace(w, 2 * v + 1);
}
}
}
return 0;
}

浙公网安备 33010602011771号