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

相关推荐
We་ct15 小时前
LeetCode 30. 串联所有单词的子串:从暴力到高效,滑动窗口优化详解
前端·算法·leetcode·typescript
-Try hard-15 小时前
数据结构|概念及单向有头链表
数据结构·算法·vim
历程里程碑15 小时前
子串----和为K的子数组
大数据·python·算法·leetcode·elasticsearch·搜索引擎·哈希算法
Aaron158815 小时前
通信灵敏度计算与雷达灵敏度计算对比分析
网络·人工智能·深度学习·算法·fpga开发·信息与通信·信号处理
2301_7903009615 小时前
C++中的命令模式
开发语言·c++·算法
2301_8223769415 小时前
C++中的解释器模式
开发语言·c++·算法
xhbaitxl15 小时前
算法学习day31-贪心算法
学习·算法·贪心算法
爱学习的阿磊15 小时前
C++代码冗余消除
开发语言·c++·算法
YuTaoShao15 小时前
【LeetCode 每日一题】2976. 转换字符串的最小成本 I
算法·leetcode·职场和发展
十年编程老舅15 小时前
冲刺米哈游|游戏开发一面面经(26 届
linux·c++·米哈游