AtCoder Beginner Contest 430(ABCDEF)

前言

第一次赛时出E!!第一次rank进前一千!!!我就说之前是因为我生病状态不好()

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int a,b,c,d;
    cin>>a>>b>>c>>d;

    if(c<a||c>=a&&d>=b)
    {
        cout<<"No"<<endl;
    }
    else
    {
        cout<<"Yes"<<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;
}

这个题就是根据化简后的条件判断一下即可,注意合法的时候要输出No()

二、B - Count Subgrid

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

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

    set<string>st;
    for(int i=0;i<=n-m;i++)
    {
        for(int j=0;j<=n-m;j++)
        {
            string s;
            for(int l=i;l<i+m;l++)
            {
                for(int r=j;r<j+m;r++)
                {
                    s+=a[l][r];
                }
            }
            st.insert(s);
        }
    }

    cout<<st.size()<<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;
}

因为数据范围不大,所以直接暴力枚举网格的两点往set里加即可。

三、C - Truck Driver

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int n,a,b;
    cin>>n>>a>>b;
    string s;
    cin>>s;
    s=" "+s;

    ll ans=0;
    vector<int>pa;
    vector<int>pb;
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='a')
        {
            pa.push_back(i);
        }
        else
        {
            pb.push_back(i);
        }

        int left=0;
        if(pb.size()>=b)
        {
            left=pb[pb.size()-b];
        }
        int right=0;
        if(pa.size()>=a)
        {
            right=pa[pa.size()-a];
        }

        if(left<right)
        {
            ans+=right-left;
        }
    }
    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;
}

这个题肯定还是考虑固定右端点,然后去找所有合法的左端点。所以考虑分别记录每个a和b的出现位置,那么从当前点往左找b个b的位置就是左端点的最左边界,往左找a个a的位置就是左端点的最右边界,那么中间的每个位置都可以作为左端点产生贡献。

四、D - Neighbor Distance

set的二分真用不明白......

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

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

    set<ll>st;
    st.insert(0);

    map<ll,ll>dis;
    dis[0]=INFLL;
    for(int i=1;i<=n;i++)
    {
        dis[a[i]]=INFLL;
    }

    ll ans=dis[0];
    for(int i=1;i<=n;i++)
    {
        ll pos=a[i];

        st.insert(pos);

        auto pre=st.lower_bound(pos);
        pre=prev(pre);
        auto nxt=st.upper_bound(pos);

        if(nxt==st.end())
        {
            ans-=dis[*pre];
            dis[*pre]=min(dis[*pre],pos-*pre);

            dis[pos]=pos-*pre;
            ans+=dis[*pre]+dis[pos];
        }
        else
        {
            ans-=dis[*pre]+dis[*nxt];
            dis[*pre]=min(dis[*pre],pos-*pre);
            dis[*nxt]=min(dis[*nxt],*nxt-pos);

            dis[pos]=min(pos-*pre,*nxt-pos);
            ans+=dis[*pre]+dis[*nxt]+dis[pos];
        }

        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;
}

很容易可以注意到,在一个位置插入一个人,可能影响的只有其相邻的两人。所以考虑直接用一个set维护目前的所有人,然后每次去二分前一个人和后一个人,只对这两个人进行修改即可。

五、E - Shift String

现在也就写写板题了......

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

const int base=499;

const int MAXN=1e6+6;

vector<ll>power(MAXN);

ll subHash(int l,int r,vector<ll>&hash)
{
    ll ans=hash[r];
    if(l>1)
    {
        ans-=hash[l-1]*power[r-l+1];
    }
    return ans;
}

void solve()
{
    string a,b;
    cin>>a>>b;
    int n=a.length();

    a=" "+a;
    b=" "+b;

    vector<ll>hash1(n+1);
    vector<ll>hash2(n+1);
    for(int i=1;i<=n;i++)
    {
        hash1[i]=hash1[i-1]*base+a[i]-'a'+1;
        hash2[i]=hash2[i-1]*base+b[i]-'a'+1;
    }

    if(hash1[n]==hash2[n])
    {
        cout<<0<<endl;
        return ;
    }

    for(int i=1;i<=n;i++)
    {
        if(subHash(1,i,hash1)==subHash(n-i+1,n,hash2)&&subHash(i+1,n,hash1)==subHash(1,n-i,hash2))
        {
            cout<<i<<endl;
            return ;
        }
    }   
    cout<<-1<<endl;
}

void init()
{
    power[0]=1;
    for(int i=1;i<MAXN;i++)
    {
        power[i]=power[i-1]*base;
    }
}

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

这个题其实看到的第一眼就能发现是字符串哈希的板题。不难发现,当把A串若干个字符移动到后面之后,若此时能和B串匹配,那么就说明A串原始的后部分和B串前部分一样,A串原始的前部分和B串的后部分一样。那么为了快速匹配两字符串,就可以使用字符串哈希,之后枚举一下A串把哪些字符移动到后面即可。

六、F - Back and Forth Filling

群友是怎么想到这个思路的......

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

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

#define endl '\n'
#define dbg(x) cout<<#x<<" "<<x<<endl
#define vdbg(a) cout<<#a<<endl; for(auto x:a) cout<<x<<" ";cout<<endl
#define INF 1e9
#define INFLL 1e18
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

void solve()
{
    int n;
    cin>>n;
    string s;
    cin>>s;
    s=" "+s;

    vector<vector<int>>g(n+1);
    vector<int>deg(n+1);
    for(int i=1;i<n;i++)
    {
        if(s[i]=='L')
        {
            g[i+1].push_back(i);
            deg[i]++;
        }
        else
        {
            g[i].push_back(i+1);
            deg[i+1]++;
        }
    }

    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        if(deg[i]==0)
        {
            q.push(i);
        }
    }

    vector<int>left(n+1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();

        for(auto v:g[u])
        {
            left[v]+=left[u]+1;
            if(--deg[v]==0)
            {
                q.push(v);
            }
        }
    }

    for(int i=1;i<=n;i++)
    {
        g[i].resize(0);
    }
    deg.resize(n+1);
    for(int i=1;i<n;i++)
    {
        if(s[i]=='R')
        {
            g[i+1].push_back(i);
            deg[i]++;
        }
        else
        {
            g[i].push_back(i+1);
            deg[i+1]++;
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(deg[i]==0)
        {
            q.push(i);
        }
    }

    vector<int>right(n+1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();

        for(auto v:g[u])
        {
            right[v]+=right[u]+1;
            if(--deg[v]==0)
            {
                q.push(v);
            }
        }
    }

    vector<int>ans(n+2);
    for(int i=1;i<=n;i++)
    {
        int l=1+left[i];
        int r=n-right[i];

        ans[l]++;
        ans[r+1]--;
    }

    for(int i=1;i<=n;i++)
    {
        ans[i]+=ans[i-1];
    }

    for(int i=1;i<=n;i++)
    {
        cout<<ans[i]<<" ";
    }
    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;
}

这个题直接就是注意到每个数字的左右关系可以形成一张有向图,那么就可以在这张有向图上进行拓扑排序,统计出每个数字可以存在的位置区间,然后根据每个数的区间差分一下求前缀和即可。因为同时存在左右关系,所以需要建正反图分别跑一遍拓扑排序。

这种拓扑排序的题多少得对这种关系很敏感才能注意到......

总结

再接再厉,加油!

END

相关推荐
百***48075 分钟前
【Golang】slice切片
开发语言·算法·golang
墨染点香18 分钟前
LeetCode 刷题【172. 阶乘后的零】
算法·leetcode·职场和发展
做怪小疯子20 分钟前
LeetCode 热题 100——链表——反转链表
算法·leetcode·链表
郝学胜-神的一滴36 分钟前
Linux命名管道:创建与原理详解
linux·运维·服务器·开发语言·c++·程序人生·个人开发
晚风(●•σ )1 小时前
C++语言程序设计——11 C语言风格输入/输出函数
c语言·开发语言·c++
恒者走天下2 小时前
秋招落定,拿到满意的offer,怎么提高自己实际的开发能力,更好的融入团队
c++
做怪小疯子2 小时前
LeetCode 热题 100——矩阵——旋转图像
算法·leetcode·矩阵
努力学习的小廉2 小时前
我爱学算法之—— BFS之最短路径问题
算法·宽度优先
天若有情6733 小时前
【c++】手撸C++ Promise:从零实现通用异步回调组件,支持链式调用+异常安全
开发语言·前端·javascript·c++·promise
高山上有一只小老虎3 小时前
构造A+B
java·算法