ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtCoder Beginner Contest 184 题解

2020-11-23 21:35:07  阅读:237  来源: 互联网

标签:AtCoder pq cout int 题解 cin 184 tie dis


AtCoder Beginner Contest 184 题解

目录

这把怎么感觉题目都比以往的ABC水啊,拜此所赐我只是程序写得慢就排名狂掉(

A - Determinant

求二阶矩阵的行列式,是小学常见自定义题目(迫真)。

#include<bits/stdc++.h>
using namespace std;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int a,b,c,d;
    cin>>a>>b>>c>>d;
    cout<<a*d-b*c<<endl;

    return 0;
}

B - Quizzes

给你一个长度\(N\)的序列\(S\),和初始分数\(X\),然后从前往后遍历序列,元素是o就加一分,是x减一分,假如已经是\(0\)分就不减分了。模拟即可。

#include<bits/stdc++.h>
using namespace std;

int n,x;
string s;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>x>>s;
    for(char& c:s)x+=(c=='o')-(c=='x'&&x);//前面for循环是从前往后遍历s,当前元素是c,后面是使用了bool的值作为int运算来简化代码
    cout<<x<<endl;

    return 0;
}

C - Super Ryuma

我们从小到大考虑步数的情况:

  • \(0\)步,此时起始位置和结束位置相同(不知道数据里有没有,还是判断一下为好)
  • \(1\)步,按照题目的定义考虑即可。
  • \(2\)步,分成斜向+短距离斜向+斜向短距离+短距离三种情况讨论即可。
  • \(3\)步,把棋盘按照国际象棋的方式黑白染色,容易发现两次斜向移动可以使得当前位置和结束位置的距离不超过\(1\),那么\(3\)步理论上可以完成所有移动了。
#include<bits/stdc++.h>
using namespace std;

bool reach(int& a,int& b,int& c,int& d){
    return a+b==c+d||a-b==c-d||abs(a-c)+abs(b-d)<=3;
}

int r1,c1,r2,c2;

bool step2(){
    for(int i=r1-3;i<=r1+3;i++){
        for(int j=c1-(3-abs(r1-i));j<=c1+(3-abs(r1-i));j++){
            if(reach(i,j,r2,c2))return true;
        }
    }
    if(abs(r1-r2)+abs(c1-c2)&1^1)return true;
    return false;
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>r1>>c1>>r2>>c2;
    if(r1==r2&&c1==c2)cout<<"0\n";
    else if(reach(r1,c1,r2,c2))cout<<"1\n";
    else if(step2())cout<<"2\n";
    else cout<<"3\n";

    return 0;
}

D - increment of coins

你拿走一个硬币,然后放回去两个硬币,容易看出其实就是添加进去一个硬币。(减去一加上二,小学生都能做的ABC(确信))

然后我们可以考虑DP,有一个状态\(f_{i,j,k}\)表示手持\(i\),\(j\)和\(k\)个三种不同的硬币时,达到不论种数至少持有\(100\)个相同的硬币时的期望操作数。

那么可以看出有\(\frac i {i+j+k}\)的几率从状态\(f_{i,j,k}\)操作到\(f_{i+1,j,k}\),操作到\(f_{i,j+1,k}\)和\(f_{i,j,k+1}\)同理。

然后你反向考虑转移就可以了。

#include<bits/stdc++.h>
using namespace std;

double f[105][105][105];
bool u[105][105][105];

double dfs(const int& a,const int& b,const int& c){
    if(a==100||b==100||c==100)return 0;
    if(u[a][b][c])return f[a][b][c];
    u[a][b][c]=true;
    return f[a][b][c]=1+(a*dfs(a+1,b,c)+b*dfs(a,b+1,c)+c*dfs(a,b,c+1))/(a+b+c);
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int a,b,c;
    cin>>a>>b>>c;
    cout<<fixed<<setprecision(10)<<dfs(a,b,c);

    return 0;
}

E - Third Avenue

主要思想还是跑最短路。

这里有一种技巧叫做虚拟结点。也就是说把每个颜色都独立建立一个点,然后把有这个颜色的格子连向它就可以显著减少边数(虽然点数会加一但是这不重要)。

这里我直接把地图转换成了一个有向图(格子和格子之间的是边权为\(1\)的无向边,但是由于虚拟结点的缘故,格子到颜色的边和颜色到格子的边权值不同)。

#include<bits/stdc++.h>
using namespace std;

int h,w,s,t;
char a[2005][2005];
vector<pair<int,int>> g[4000035];
int dis[4000035];

inline int get(const int& i,const int& j){
    return i*w-w+j;
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>h>>w;
    for(int i=1;i<=h;i++){
        cin>>a[i]+1;
        for(int j=1;j<=w;j++){
            if(a[i][j]=='S')s=get(i,j);
            if(a[i][j]=='G')t=get(i,j);
            if(a[i][j]!='#'){
                if(i>1)g[get(i,j)].emplace_back(get(i-1,j),1);
                if(i<h)g[get(i,j)].emplace_back(get(i+1,j),1);
                if(j>1)g[get(i,j)].emplace_back(get(i,j-1),1);
                if(j<w)g[get(i,j)].emplace_back(get(i,j+1),1);
                if(a[i][j]>='a'&&a[i][j]<='z'){
                    g[get(i,j)].emplace_back(h*w+a[i][j]-'a'+1,0);
                    g[h*w+a[i][j]-'a'+1].emplace_back(get(i,j),1);
                }
            }
        }
    }
    memset(dis,0x3f,sizeof(dis));
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
    dis[s]=0;
    pq.emplace(0,s);
    while(!pq.empty()){
        int x=pq.top().second,d=pq.top().first;
        pq.pop();
        if(d>dis[x])continue;
        for(pair<int,int>& e:g[x]){
            int& y=e.first,& z=e.second;
            if(dis[y]>d+z)pq.emplace(dis[y]=d+z,y);
        }
    }
    if(dis[t]==0x3f3f3f3f)dis[t]=-1;
    cout<<dis[t]<<endl;

    return 0;
}

F - Programming Contest

折半枚举,首先把题目分成两半,通过子集枚举的方式预处理出前一半的所有不同的选择题目的方式的时间和,后一半同理。

然后排个序,通过二分查找的方式(当然你可以用two pointers的方式来达到线性的时间,但是排序都已经多出来一个对数了你还管这个干嘛),我们可以查找出每个前一半的题目中的,选择题目的方式对应的,在不超过比赛时间的情况下,时间最大的后一半的选择方式。

你也可以像我一样通过把\(N\)扩展到\(40\)的方式实现一种奇怪的\(O(N)\)做法(

#include<bits/stdc++.h>
using namespace std;

int n,t,a[45],s[1<<20|5],f[1<<20|5],ans;

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin>>n>>t;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int msk=0;msk<1<<20;msk++){
        for(int i=0;i<20;i++)if(msk>>i&1){
            s[msk]=min(t+1,s[msk]+a[i]);
            f[msk]=min(t+1,f[msk]+a[i+20]);
        }
    }
    sort(s,s+(1<<20|1));
    sort(f,f+(1<<20|1));
    for(int i=0;i<(1<<20|1)&&s[i]<=t;i++){
        ans=max(ans,s[i]+f[upper_bound(f,f+(1<<20|1),t-s[i])-f-1]);
    }
    cout<<ans<<endl;

    return 0;
}

标签:AtCoder,pq,cout,int,题解,cin,184,tie,dis
来源: https://www.cnblogs.com/BlahDuckling747/p/AtCoder_Beginner_Contest_184_Solution.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有