KAJIMA CORPORATION CONTEST 2024(AtCoder Beginner Contest 340)(A~D)

A - Arithmetic Progression

给你A,B,D,输出A,A+D,A+2*D,...到B为止,一个循环就可以解决。

#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int a,b,d;

void solve(){
    cin>>a>>b>>d;
    for(int i=a;i<=b;i+=d)cout<<i<<" ";
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t=1;
    while(t--)solve();
    return 0;
}

B - Append

输入1,往序列后面添加x。

输入2,查询从后往前第k个数。

可以用数组模拟扩展,也可以用vector直接来做。

#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int q,opt,x,k;

vector<int>a;

void solve(){
    cin>>q;
    while(q--){
        cin>>opt;
        if(opt==1){
            cin>>x;
            a.push_back(x);
        }else if(opt==2){
            cin>>k;
            cout<<a[a.size()-k]<<endl;
        }
    }
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t=1;
    while(t--)solve();
    return 0;
}

补题:C - Divide and Divide

给你一个数N,写在黑板上。对黑板上大于等于2的执行操作,设其为x,擦除x(答案就是擦除的总数),写上x/2向下取整和x/2向上取整。

N<=1e17,数组开不下的话只能动态dp或者记忆化搜索,因为下面的正常搜索写出来测试了大概10秒钟也不出答案,那复杂度就超了,想办法剪枝或者记忆重复搜索的内容。

void dfs(int x){
if(x<2)return;
ans+=x;
if(x%2==1)dfs(x>>1),dfs(x/2+1);
else dfs(x>>1),dfs(x>>1);
}

因为是递归(相当于调用函数,两个dfs的值是一样的),所以dfs(x>>1)可以先算出来一个,然后直接乘以二。

int dfs(int x){
    if(x<2)return 0;
    if(x&1){
        return dfs(x>>1)+dfs((x>>1)+1)+x;
    }else{
        return dfs(x>>1)*2+x;
    }
}

但是这么写还是过不了,1e17进去能过,但是1e17-1,奇数进去刚好超时一点点。再结合递归性质,一大堆递归都是先放好不执行,一条路走到底再去走别的,所以可以加一个map记录计算过的数。

map<int,int>f;

int dfs(int x){
    if(x<2)return 0;
    if(f[x])return f[x];
    if(x&1){
        return dfs(x>>1)+dfs((x>>1)+1)+x;
    }else{
        return f[x]=dfs(x>>1)*2+x;
    }
}

这样就可以1msAC了!

完整代码

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;

int n;

map<int,int>f;

int dfs(int x){
    if(x<2)return 0;
    if(f[x])return f[x];
    if(x&1){
        return dfs(x>>1)+dfs((x>>1)+1)+x;
    }else{
        return f[x]=dfs(x>>1)*2+x;
    }
}

void solve(){
    cin>>n;

    cout<<dfs(n);
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t=1;
    while(t--)solve();
    return 0;
}

D - Super Takahashi Bros.

题目应该是比较容易读懂的,每一个舞台都可以花费A[i]到达下一个舞台,或者花费B[i]到达X[i]舞台。

如果只考虑当前这个点怎么做单次决策那就做不了这道题,因为X[i]会多次来回跳,所以正常的贪心和dp都做不了这道题。

舞台 i 能到 i+1 还能到 x[i],还有花费,如果能想到建图,那这道题就解决了。

因为权值都是正的,N=2e5,所以采用优先队列优化的dijkstra算法(正常的dj算法不一定能过,N*N复杂度有风险,这道题节点固定为N个,所以优先队列来优化选点更好)

#include <bits/stdc++.h>
#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;
const int N=2e5+5,MAX=LONG_LONG_MAX>>1;

int n,a,b,x,dist[N];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
vector<pair<int,int>>e[N];
bitset<N>vis;

void solve(){
    cin>>n;
    per(i,1,n-1){
        cin>>a>>b>>x;
        e[i].push_back({a,i+1});
        e[i].push_back({b,x});
    }

    per(i,2,n)dist[i]=MAX;
    q.push({0,1});
    while(!q.empty()){
        int now=q.top().second;
        int nowDis=q.top().first;
        q.pop();

        if(vis[now])continue;
        vis[now]=true;
        for(auto i:e[now]){
            int toNextLength=i.first;
            int nxt=i.second;

            if(dist[nxt]>dist[now]+toNextLength){
                dist[nxt]=dist[now]+toNextLength;
                if(!vis[nxt]){
                    q.push({dist[nxt],nxt});
                }
            }
        }
    }

    cout<<dist[n]<<endl;
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(nullptr);
    int t=1;
    while(t--)solve();
    return 0;
}

记得开longlong。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值