比赛链接:AtCoder Beginner Contest 395
A-Strictly Increasing
思路:模拟即可。时间复杂度 O(n) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
void solve()
{
int n;
cin >> n;
vector<int>a(n+5,0);
rep(i,1,n)
cin >> a[i];
rep(i,2,n)
{
if(a[i]<=a[i-1])
{
cout << "No" << endl;
return;
}
}
cout << "Yes" << endl;
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}
B-Make Targ
思路:题目讲得很清楚了,模拟即可。 时间复杂度 O(n^3) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
char a[55][55];
void solve()
{
int n;
cin >> n;
rep(i,1,n)
{
int j=n+1-i;
if(i<=j)
{
rep(c,i,j)
{
rep(r,i,j)
{
if(i%2!=0)
a[c][r]='#';
else
a[c][r]='.';
}
}
}
}
rep(i,1,n)
{
rep(j,1,n)
cout << a[i][j];
cout << endl;
}
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}
C-Shortest Duplicate Subarray
思路:思考发现,我们可以将每个重复元素的位置按照种类存放起来(可以用 map 嵌套 vector 轻松实现这点),然后逐个遍历每种重复元素的位置,寻找间隔最小值。时间复杂度 O(n) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
LL lowbit(LL x) { return x & (-x); }
int a[200005];
unordered_map<int,vector<int>>mp;
unordered_map<int,int>vs;
void solve()
{
int n;
cin >> n;
rep(i,1,n)
{
cin>> a[i];
vs[a[i]]++;
}
rep(i,1,n)
{
if(vs[a[i]]!=0)
mp[a[i]].push_back(i);
}
int mind=INT_MAX;
for(auto &it:mp)
{
int lastp=it.second.front();
for(auto &ut:it.second)
{
if(ut==it.second.front())
continue;
mind=min(mind,ut-lastp+1);
lastp=ut;
}
}
if(mind==INT_MAX)
cout << -1;
else
cout << mind;
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}
D-Pigeon Swap
思路:我们自然想到用一个数组 gedelong[i] 来记录鸽子 i 的笼子的编号,先尝试按照题意模拟操作一遍,发现难点在于操作 2 将 a 和 b 笼子的鸽子全部互换,如果暴力操作必定超时,于是我们想到可以只交换 a b 笼子的位置,这样做会引入新的数组 longdepos[i] 记录编号为 i 的笼子的位置,posdelong[i] 记录位置为 i 的笼子的编号。我们根据新的逻辑关系模拟即可。时间复杂度 O(n) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
void solve()
{
int n,q;
cin >> n >> q;
vector<int>gedelong(n+5);
vector<int>longdepos(n+5);
vector<int>posdelong(n+5);
rep(i,1,n)
{
gedelong[i]=i;
longdepos[i]=i;
posdelong[i]=i;
}
while(q--)
{
int num;
cin >> num;
if(num==1)
{
int a,b;
cin >> a >> b;
gedelong[a]=posdelong[b];
}
else if(num==2)
{
int a,b;
cin >> a >> b;
swap(longdepos[posdelong[a]],longdepos[posdelong[b]]);
swap(posdelong[a],posdelong[b]);
}
else if(num==3)
{
int a;
cin >> a;
cout << longdepos[gedelong[a]] << endl;
}
}
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}
E-Flip Edge
思路:注意到每次可以有反转所有边的操作,那么我们相当于有了两个图,建立分层图然后用迪杰斯特拉算法求最短路,由于没有规定终点必须在哪个图里,我们取终点在正图和在反图的最小值即可。时间复杂度 O(n log n) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS \
ios::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
const int MAXN = 2e5 + 5;
vector<pair<int,int>>G[MAXN*2];
bool vsd[MAXN*2];
LL dis[MAXN*2];
void solve()
{
int n,m,x;
cin >> n >> m >> x;
rep(i,1,m)
{
int u,v;
cin >> u >> v;
G[u].emplace_back(v,1);//正图
G[v+n].emplace_back(u+n,1);//反图
}
rep(i,1,n)//正图到反图的边(均为无向)
{
G[i].emplace_back(i+n,x);
G[i+n].emplace_back(i,x);
}
priority_queue<pair<LL,int>, vector<pair<LL,int>>,greater<pair<LL,int>>>q;
fill(dis,dis+1+2*n,1e18);
q.push({dis[1] = 0,1});
while(!q.empty())
{
auto [_,v]=q.top();
q.pop();
if(vsd[v])
continue;
vsd[v]=1;
for(auto [to,w]:G[v])
{
if(dis[to]>dis[v]+w)
{
dis[to]=dis[v]+w;
q.push({dis[to],to});
}
}
}
cout << min((LL)dis[n],(LL)dis[2*n]) << endl;
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}
F-Smooth Occlusion
思路:容易发现,最后的代价应该等于所有的 u[i] 与 d[i] 的和 sum 减去 n*H,为了求得最小的代价,我们应让 H 最大,于是问题转化为在两个长度为n的数组u和d中,寻找一个最大的 H 使得 u[i] + d[i] == H,abs(u[i] - u[i+1]) <= x 。我们观察发现 H 具有单调性(证明过程略去),于是考虑对 H 二分答案。我们来构造判断函数:假设 mid 可以使得操作合法,根据条件通过数学推导(推导过程略去)我们可以发现每一个 u[i] 允许选择的值都在 [ max(mid - d[i], lstL[i] - x), min(u[i], lstR[i] + x) ]之内,其中 lstL 和 lstR 为上一个数可取范围的左界和右界,如果范围存在返回true。注意 long long 和负数,以及 H 的范围。时间复杂度 O(n log n) 可以通过此题。
#include <bits/stdc++.h>
#define endl '\n'
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define LL long long
#define fir first
#define sec second
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
LL lowbit(LL x) { return x & (-x); }
const int MAXN=2e5+5;
int n,x;
int u[MAXN], d[MAXN];
bool P(LL mid)
{
LL lstL=max(mid-(LL)d[1],(LL)0),lstR=(LL)u[1];
rep(i,2,n)
{
lstL=max(lstL-(LL)x,max(mid-(LL)d[i],(LL)0));
lstR=min((LL)u[i],lstR+(LL)x);
if(lstL>lstR)
return 0;
}
return 1;
}
void solve()
{
cin >> n >> x;
LL sum=0;
LL minn=LLONG_MAX;
rep(i,1,n)
{
cin >> u[i] >> d[i];
minn=min(minn,(LL)(u[i]+d[i]));
sum+=(LL)(u[i]+d[i]);
}
LL l=0,r=minn,mid,ans;//由于任意的u[i]+d[i]必须>=H,所以二分H的范围也要在此范围
while(l<=r)
{
if(P(mid=(l+r)>>1))
ans=mid,l=mid+1;
else
r=mid-1;
}
cout << sum-n*ans << endl;
}
int main()
{
IOS;
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}