AtCoder Beginner Contest 436(ABCDEF)

前言

现在也是好起来了,能经常切E了!>v<

这么看我们新生赛的难度差不多也就abc里D或者E的难度,不知道为啥自己能开得那么慢,也许是客场作战+太冷+赛时红温的原因(?

一、A - o-padding

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n;
    cin>>n;
    string s;
    cin>>s;
    
    while(s.length()<n)
    {
        s="o"+s;
    }
    cout<<s<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

纯模拟,只要长度不够就往前补就行。

二、B - Magic Square

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n;
    cin>>n;
    
    vector<vector<int>>g(n,vector<int>(n));

    g[0][(n-1)/2]=1;

    int x=0;
    int y=(n-1)/2;
    int k=2;
    while(k<=n*n)
    {
        if(g[(x-1+n)%n][(y+1)%n]==0)
        {
            g[(x-1+n)%n][(y+1)%n]=k++;
            x=(x-1+n)%n;
            y=(y+1)%n;
        }
        else
        {
            g[(x+1)%n][y]=k++;
            x=(x+1)%n;
        }
    }

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cout<<g[i][j]<<" ";
        }
        cout<<endl;
    }
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

这个题也还好,直接根据题意模拟着填就可以了,反正说可以证明一定能全填上。

三、C - 2x2 Placing

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n,m;
    cin>>n>>m;

    set<pii>st;

    auto check=[&](int x,int y)->bool
    {
        if((st.find({x,y})==st.end())&&(st.find({x+1,y})==st.end())&&(st.find({x,y+1})==st.end())&&(st.find({x+1,y+1})==st.end()))
        {
            return true;
        }
        return false;
    };

    int x,y;
    while(m--)
    {
        cin>>x>>y;

        if(check(x,y))
        {
            st.insert({x,y});
            st.insert({x+1,y});
            st.insert({x,y+1});
            st.insert({x+1,y+1});
        }
    }

    cout<<st.size()/4<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

这个题因为n很大,所以肯定就不能直接模拟了。那么就可以考虑用set维护之前涂过色的格子,所以每次只需要check一下当前要覆盖的四个格子是否以前被涂过色了。如果没有就往set里加上当前操作涂的四个格子,那么时间空间复杂度就都是和操作数相关的了。

四、D - Teleport Maze

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

void solve()
{
    int n,m;
    cin>>n>>m;
    vector<string>g(n);
    for(int i=0;i<n;i++)
    {
        cin>>g[i];
    }

    map<char,vector<pii>>mp;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(g[i][j]>='a'&&g[i][j]<='z')
            {
                mp[g[i][j]].push_back({i,j});
            }
        }
    }

    queue<pii>q;
    q.push({0,0});
    vector<vector<int>>vis(n,vector<int>(m));
    vis[0][0]=1;

    int level=0;
    while(!q.empty())
    {
        int sz=q.size();
        for(int i=1;i<=sz;i++)
        {
            auto [x,y]=q.front();
            q.pop();

            if(x==n-1&&y==m-1)
            {
                cout<<level<<endl;
                return ;
            }

            for(int j=0;j<4;j++)
            {
                int nx=x+dx[j];
                int ny=y+dy[j];

                if(nx>=0&&nx<n&&ny>=0&&ny<m&&g[nx][ny]!='#'&&!vis[nx][ny])
                {
                    q.push({nx,ny});
                    vis[nx][ny]=1;
                }
            }

            if(g[x][y]>='a'&&g[x][y]<='z')
            {
                vector<pii>next;
                for(auto [nx,ny]:mp[g[x][y]])
                {
                    if(!vis[nx][ny])
                    {
                        q.push({nx,ny});
                        vis[nx][ny]=1;
                        next.push_back({nx,ny});
                    }
                }
                mp[g[x][y]]=next;
            }
        }

        level++;
    }
    cout<<-1<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

这个题其实也就是bfs的板子题。由于存在"传送门",所以首先考虑统计每个字符出现的所有格子,然后就去跑bfs。按层进行bfs的过程中,每次除了考虑上下左右四个方向的格子,如果当前格子是字母,那么就可以传送到别的格子,那么每次就是考虑所有能到的格子里没vis过的,然后下一次碰到这个字母时就只需要考虑这些没vis过的格子即可。

不加最后的判vis更新感觉会TLE,没试过,vp的时候直觉告诉我应该加就直接加了()

五、E - Minimum Swap

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

const int MAXN=3e5+5;

vector<int>father(MAXN);
vector<ll>sz(MAXN);

int n;

void build()
{
    for(int i=1;i<=n;i++)
    {
        father[i]=i;
        sz[i]=1;
    }
}

int find(int i)
{
    if(i!=father[i])
    {
        father[i]=find(father[i]);
    }
    return father[i];
}

void merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);

    if(fx!=fy)
    {
        father[fx]=fy;
        sz[fy]+=sz[fx];
    }
}

void solve()
{
    cin>>n;

    build();
    
    for(int i=1,x;i<=n;i++)
    {
        cin>>x;
        merge(i,x);
    }

    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        if(i==find(i))
        {
            ans+=sz[i]+(sz[i]*(sz[i]-3))/2;
        }
    }
    cout<<ans<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

这题一眼上去确实有点可怕,但其实多举几个例子玩一下会发现其实还好。

对于当前位置i上的数a[i],考虑建立一条(i,a[i])的边,由于是排列,那么肯定会形成若干个环。之后还是举大量例子观察可以发现,对于每个环形成的这个多边形,第一步选择任意两点交换必然可以达到最优解。那么若这个环的大小为n,能形成的方案数就是n*(n-1)/2。那么就只需要用并查集连边,记录每个连通块的大小,然后考虑每个连通块即可,因为必然构成环。

不懂vp的时候为什么用的这个公式,可能想的是除了原本环上的边还能连几条吧,反正这俩公式也是一样的()

六、F - Starry Landscape Photo

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

/*   /\_/\
*   (= ._.)
*   / >  \>
*/

/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/

#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};

const int MAXN=5e5+5;

vector<int>tree(MAXN);

int lowbit(int i)
{
    return i&-i;
}

void add(int i,int v,int n)
{
    while(i<=n)
    {
        tree[i]+=v;
        i+=lowbit(i);
    }
}

int sum(int i)
{
    int ans=0;
    while(i>0)
    {
        ans+=tree[i];
        i-=lowbit(i);
    }
    return ans;
}

void solve()
{
    int n;
    cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }

    //考虑枚举星星最大值为k时的方案数
    //那么在找到k这颗星星的位置后,因为此时只能拍到小于等于k的星星
    //所以在左右分别找出小于等于k的星星个数x和y个,此时对答案的贡献就是(x+1)*(y+1)
    
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        //a[i]左侧小于a[i]的个数
        ll pre=sum(a[i]);

        ans+=(pre+1)*(a[i]-pre);

        add(a[i],1,n);
    }
    cout<<ans<<endl;
}

void init()
{
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    //cin>>t;
    init();
    while(t--)
    {
        solve();    
    }
    return 0;
}

其实这题就是一眼方法是需要考虑固定一个,然后去找另外两个的类型,但vp的时候光往固定右端点考虑了,压根没往固定b的方向想,思维还是太僵化了......

考虑枚举星星最大值为k时对答案的贡献,那么在找到亮度为k的这颗星星的位置后,因为此时只能拍到亮度小于等于k的星星,所以在左右找出亮度小于k的星星个数分别为left和right,此时对答案的贡献就是(left+1)*(right+1)。那么就可以考虑用树状数组维护,在从左往右枚举的过程中,对于当前星星的亮度a[i],树状数组里小于等于a[i]的个数就是左侧小于的个数pre,那么右侧小于的个数就是a[i]-pre-1,相乘统计贡献即可。

总结

还得练,希望寒假能练出稳切F的水平!加油!

END

相关推荐
fie88892 小时前
广义 S 变换(GST)地震信号时频谱
算法
辣机小司3 小时前
【软件设计师】自编思维导图和学习资料分享(中级已过)
java·c++·软考·软件设计师
json{shen:"jing"}3 小时前
1-C语言的数据类型
c语言·c++·算法
im_AMBER3 小时前
数据结构 13 图 | 哈希表 | 树
数据结构·笔记·学习·算法·散列表
LYFlied3 小时前
【算法解题模板】动态规划:从暴力递归到优雅状态转移的进阶之路
数据结构·算法·leetcode·面试·动态规划
名誉寒冰4 小时前
GDB 调试与 Core Dump(段错误)排查指南(Linux/C/C++)
linux·c语言·c++
Hcoco_me4 小时前
RTMPose_JSON相关解读
算法·数据挖掘·json·聚类
高洁014 小时前
DNN案例一步步构建深层神经网络(二)
人工智能·python·深度学习·算法·机器学习
aini_lovee4 小时前
改进遗传算法求解VRP问题时的局部搜索能力
开发语言·算法·matlab