ABC题解(ABCDEF)

比赛链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值