AtCoder Beginner Contest 344 (A~F)

文章展示了五段C++代码,涉及字符串处理、数组操作、集合优化、动态规划和链表问题,展示了在IT竞赛中可能遇到的数据结构和算法解决方案。
摘要由CSDN通过智能技术生成

比赛地址传送门

A - Spoiler

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string line;
    cin>>line;
    int l=0,r=line.length()-1;
    while(line[l]!='|') l++;
    while(line[r]!='|') r--;
    for(int i=0;i<line.length();i++) {
        if(i<l||i>r) cout<<line[i];
    }

    return 0;
}

B - Delimiter

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    vector<ll> ans;
    int x;
    while(cin>>x) {
        ans.push_back(x);
        if(x==0) break;
    }

    reverse(ans.begin(),ans.end());
    for(auto temp: ans) {
        cout<<temp<<'\n';
    }
    return 0;
}

C - A+B+C

可以发现数据范围不大,可以将所有求和结果提前枚举放进集合里,每次查询就看看集合里面有没有这个数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int n,m,l;
    cin>>n;
    vector<ll> a(n);
    for(int i=0;i<n;i++) cin>>a[i];
    cin>>m;
    vector<ll> b(m);
    for(int i=0;i<m;i++) cin>>b[i];
    cin>>l;
    set<ll> c;
    for(int i=0;i<l;i++) {
        int x;
        cin>>x;
        for(int j=0;j<n;j++) {
            for(int k=0;k<m;k++) {
                c.insert(x+a[j]+b[k]);
            }
        }
    }

    int t;
    cin>>t;
    while(t--) {
        ll q;
        cin>>q;
        cout<<(c.count(q)?"Yes":"No")<<'\n';
    }
    return 0;
}

D - String Bags*

有点 是分组背包问题,考虑维护数组 dp[i][j] 表示第 i 组中选好了前 j 个字符的最小花费。那么对于每一组中的每个单词,枚举所有 k ∈ [ 0 , S . l e n g t h ) k ∈ [0, S.length) k[0,S.length) 看看这个单词是否能放在第 k 个位置,如果可以的话,那么 dp[i][j] = min(dp[i-1][k-1]+1)
可以用滚动数组优化空间

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int tlen,len,a;
string t;
bool cmp(string a,string b)
{
    return a.length()>b.length();
}
void solve(vector<int> &f)
{
    vector<int> temp(110,1e9);
    for(int j=1;j<=a;j++) {
        string word;
        cin>>word;
        len=word.length();
        for(int k=0;k<=tlen-len;k++) {
            if(t.substr(k,len)==word) {

                if(k==0) temp[len-1]=1;
                else temp[k+len-1]=min(temp[k+len-1],f[k-1]+1);
            }
        }
    }
    for(int k=0;k<=tlen;k++)
        f[k]=min(f[k],temp[k]);
}
int main()
{
    int n;
    cin>>t>>n;
    tlen=t.length();
    vector<int> f(110,1e9);
    for(int i=1;i<=n;i++) {
        cin>>a;
        solve(f);
    }

    if(f[tlen-1]==1e9) cout<<-1;
    else cout<<f[tlen-1]<<'\n';
    return 0;
}

E - Insert or Erase

典型链表问题,普通链表插入 O ( 1 ) O(1) O(1),查询 O ( n ) O(n) O(n),但本题中每个数组仅会出现一次,可以用 map 将查询操作变为 O ( l o g n ) O(logn) O(logn)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// int nex[200010],pre[200010];
map<int,int> nex,pre;
int _front=-1;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin>>n;
    int last=-1;
    for(int i=1;i<=n;i++) {
        int x;
        cin>>x;
        nex[x]=-1,pre[x]=-1;
        if(_front==-1) _front=x;
        if(last!=-1) nex[last]=x;
        pre[x]=last;
        last=x;
    }

    int q;
    cin>>q;
    while(q--) {
        int op,x,y;
        cin>>op>>x;
        if(op==1) {
            cin>>y;
            nex[y]=nex[x];
            pre[y]=x;
            if(nex[x]!=-1) pre[nex[x]]=y;
            nex[x]=y;
        } else {
            int z=pre[x];
            if(nex[x]!=-1) pre[nex[x]]=z;
            if(z==-1) {
                pre[nex[x]]=-1;
                _front=nex[x];
            } else {
                nex[z]=nex[x];
            }
        }
    }

    while(_front!=-1) {
        cout<<_front<<' ';
        _front=nex[_front];
    }
    return 0;
}

F - Earn to Advance

乍一看很简单,直接bfs搜索即可,但是试了一下发现第二个样例就过不去,时间复杂度过高,于是又想到了 dp ,用 dp[i][j] 来简单维护到坐标 ( i , j ) (i,j) (i,j) 的最短花费,贪心的想如果钱不够就留下来挖宝,如果够了就出发,想一会就发现不对。

开摆!

又到了观摩大佬代码的时间~
大佬题解
因为充值一次的代价是相同的,那么选择充钱多的点来充钱一定是最优解。如果起点钱最多,那完全可以在起点充好钱一股气走到终点,如果中间有个点钱很多,那么我们可以在起点充钱充到足够支持我们走到那个钱更多的点。不难发现,假设我们选择充钱的点为 a 1 、 a 2 、 a 3 、 . . . a_1、 a_2、 a_3、 ... a1a2a3... 那么,当且仅当 M a 1 < M a 2 < M a 3 . . . M_{a_1} < M_{a_2} < M_{a_3} ... Ma1Ma2<Ma3... 时才是最优的(M是钱数),对于每个点 x,dp维护它能走到的所有比它钱多的点 y 的花费, 如果从 x 走向 y 的花费更小或者两者花费相同但是从 x 走钱更多,则用 x 点更新 y 点

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int n;
    cin>>n;
    vector p(n,vector<int>(n));
    vector r(n,vector<int>(n-1));
    vector d(n-1,vector<int>(n));
    for(auto &i: p) {
        for(auto &j: i) {
            cin>>j;
        }
    }
    for(auto &i: r) {
        for(auto &j: i) {
            cin>>j;
        }
    }
    for(auto &i: d) {
        for(auto &j: i) {
            cin>>j;
        }
    }

    vector dp(n,vector<array<ll,2>>(n,{(ll)1e18,0}));
    dp[0][0]={0,0};
    for(int i=0;i<n;i++) {
        for(int j=0;j<n;j++) {

            vector dist(n,vector<ll>(n,1e18));
            dist[i][j]=0;
            for(int k=i;k<n;k++) {
                for(int l=j;l<n;l++) {
                    if(k) dist[k][l]=min(dist[k][l],dist[k-1][l]+d[k-1][l]);
                    if(l) dist[k][l]=min(dist[k][l],dist[k][l-1]+r[k][l-1]);
                }
            }

            for(int k=i;k<n;k++) {
                for(int l=j;l<n;l++) {

                    if(k!=n-1&&l!=n-1&&p[k][l]<p[i][j]) 
                        continue;

                    ll step=dp[i][j][0],money=dp[i][j][1];
                    ll cost=max(0ll,(dist[k][l]-money+p[i][j]-1)/p[i][j]);
                    ll _money=money+cost*p[i][j]-dist[k][l];
                    ll _step=step+cost+(k-i)+(l-j);
                    if(_step<dp[k][l][0]||_step==dp[k][l][0]&&_money>dp[k][l][1])
                        dp[k][l]={_step,_money};
                }
            }
        }
    }

    cout<<dp[n-1][n-1][0]<<'\n';
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值