Atcoder Beginner Contest 197

A - Rotate

直接输出

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    cin>>s;
    cout<<s[1]<<s[2]<<s[0];
}

B - Visibility

题目保证选择的点没有障碍,那么就以这个点向上下左右遍历计数即可。

最后答案减去3,因为多加三次该点

#include<bits/stdc++.h>
using namespace std;
const int N=105;
char a[N][N];
int main()
{
    int h,w,x,y;
    set<pair<int,int>>st;
    cin>>h>>w>>x>>y;
    for(int i=1;i<=h;i++)
        for(int j=1;j<=w;j++)
            cin>>a[i][j];
    int res=0;
    for(int i=y;i<=w;i++)
    {
        if(a[x][i]=='.') res++;
        else break;
    }
    for(int i=y;i>0;i--)
    {
        if(a[x][i]=='.') res++;
        else break;
    }
    for(int i=x;i<=h;i++)
    {
        if(a[i][y]=='.') res++;
        else break;
    }
    for(int i=x;i>0;i--)
    {
        if(a[i][y]=='.')res++;
        else break;
    }
    cout<<res-3;
}

C - ORXOR

因为是OR 和 XOR,结果几个数异或的结果大小与这几个数本身大小没有绝对的关系,我们看到N有20,所以可以利用状态压缩,遍历所有可能的分组方式,最后求得最大值。

#include<bits/stdc++.h>
using namespace std;
const int N=21;
typedef long long ll;
ll a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];
    int res=INT_MAX;
    for(int i=0;i<1<<(n-1);i++)
    {
        int orn=0;
        int xorn=0;
        for(int j=0;j<=n;j++)
        {
            if(j<n) orn|=a[j];
            if(j==n || ((i>>j)&1)) xorn^=orn,orn=0;
        }
        res=min(res,xorn);
    }
    cout<<res;
}

D - Opposite

第一次做这样的题。

就是一个数学题,给定n个点,告诉你第0个点和第n/2个点的坐标,又知这n个点以逆时针方式表示,让你求第一个点的坐标。

很显然我们可以连接给定的两个点,那么他们的中点就是这个圆的中心,那么就可以利用第0个点求得一个向量,那么该向量逆时针旋转2π/n度,就是第一个点的坐标。

而对于向量旋转后的坐标,可以自行计算,属于高中知识,也可以背过拿来用

向量 a=(x,y) —> a’=(x’,y’)

顺时针旋转 α得到的向量的坐标为 (x′,y′)
x′ = sinα∗y + cosα∗x , y′ = cosα∗y − sinα∗x

逆时针旋转 α得到的向量的坐标为 (x′,y′)
x′ = sinα∗x - cosα∗y , y′ = cosα∗y + sinα∗x

#include<bits/stdc++.h>
using namespace std;
const int N=21;
typedef long long ll;
ll a[N];
int main()
{
    int n;
    cin>>n;
    double xs,ys,xm,ym;
    cin>>xs>>ys>>xm>>ym;
    double xc=(xs+xm)/2.;
    double yc=(ys+ym)/2.;
    
    double x0=xs-xc;
    double y0=ys-yc;
    double div=(2*3.14159265358979)/n;
    
    double x1=x0*cos(div) - y0*sin(div) + xc;
    double y1=y0*cos(div) + x0*sin(div) + yc;
    
    cout<<x1<<" "<<y1;
}

E - Traveler

非常好的一个DP问题。

大体思路为,要以颜色id递增顺序拿到球,那么必然要从这个颜色最左侧或最右侧出现的位置拿到,再去到另一边,那么就可以预先记录好各个颜色最左侧和最右侧出现的位置,然后DP[i][0/1]分别代表拿到第i种颜色球时,位于最左侧所花的时间和位于最右侧所花费的时间。

具体实现中,共三种情况分析,分别进行转移,代码更好理解。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
typedef long long ll;
struct node{
    ll dis,id;
}a[N];
ll dp[N][2];
ll l[N],r[N];
ll vis[N];
vector<ll>ti;
void update(ll prepos,ll predis,ll cur)
{
    if(prepos<l[cur]){
        dp[cur][0]=min(dp[cur][0],r[cur]-prepos+r[cur]-l[cur]+predis);
        dp[cur][1]=min(dp[cur][1],r[cur]-prepos+predis);
    }
    else if(prepos>=l[cur] && prepos<=r[cur]){
        dp[cur][0]=min(dp[cur][0],r[cur]-prepos+r[cur]-l[cur]+predis);
        dp[cur][1]=min(dp[cur][1],prepos-l[cur]+r[cur]-l[cur]+predis);
    }
    else{
        dp[cur][0]=min(dp[cur][0],prepos-l[cur]+predis);
        dp[cur][1]=min(dp[cur][1],prepos-l[cur]+r[cur]-l[cur]+predis);
    }
}
int main()
{
    int n;
    cin>>n;
    ti.push_back(0);
    memset(dp,0x3f,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        cin>>a[i].dis>>a[i].id;
        if(!vis[a[i].id]){
            ti.push_back(a[i].id);
            vis[a[i].id]=1;
            l[a[i].id]=a[i].dis;
            r[a[i].id]=a[i].dis;
            continue;
        }
        l[a[i].id]=min(l[a[i].id],a[i].dis);
        r[a[i].id]=max(r[a[i].id],a[i].dis);
    }
    sort(ti.begin(),ti.end());
    int len=ti.size();
    dp[0][0]=0;
    dp[0][1]=0;
    for(int i=1;i<len;i++)
    {
        ll pre=ti[i-1];
        ll cur=ti[i];
        update(l[pre],dp[pre][0],cur);
        update(r[pre],dp[pre][1],cur);
    }
    int t=ti[len-1];
    ll ans=min(dp[t][0]+abs(l[t]),dp[t][1]+abs(r[t]));
    cout<<ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值