【ATcoder】abc361 B-F题解 atcoder beginner contest361

Posted on 2024-07-08 00:47  木易meow  阅读(144)  评论(0编辑  收藏  举报

B-Intersection of Cuboids

传送门:

B - Intersection of Cuboids (atcoder.jp)

简单题意

给定两个长方体 判断是否有重合体积

思路:

假设有重合体积,那么重合部分一定是个长方体。如果是长方体一定在三个坐标轴的投影都有一段长度。所以问题转化为判断两个长方体在三个坐标轴上是否都有一段交集

code:

#include<bits/stdc++.h>

#define endl '\n'

#define int long long

using namespace std;

const int MAXN=2e5+10;

int a[7],b[7];

void sol(){

    for(int i=1;i<=6;i++)cin>>a[i];

    for(int i=1;i<=6;i++)cin>>b[i];

    int f=1;

    if(b[1]>=a[4] || a[1]>=b[4])f=0;

    if(b[2]>=a[5] || a[2]>=b[5])f=0;

    if(b[3]>=a[6] || a[3]>=b[6])f=0;

    if(!f)cout<<"No"<<endl;

    else cout<<"Yes"<<endl;

}

signed main(){

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

    sol();

}

C Make Them Narrow

传送门:

C - Make Them Narrow (atcoder.jp)

简述题意:

可以从n个数里面移走k个数,求出移走后的最小极差

思路:

因为极差只与最大最小有关,所以分别讨论从小开始移走0-k个(对应从大的一端移走k-i个)的极差。

code

#include<bits/stdc++.h>

#define endl '\n'

#define int long long

using namespace std;

const int MAXN=2e5+10;

const int inf=0x3f3f3f3f;

int a[MAXN];

bool cmp(int x,int y){

    return x<y;

}

void sol(){

    int n,k;

    cin>>n>>k;

    for(int i=1;i<=n;i++){

        cin>>a[i];

    }

    sort(a+1,a+n+1,cmp);

    int ans=inf;

    for(int i=0;i<=k;i++){

        int res=a[n-k+i]-a[1+i];

        ans=min(ans,res);

    }

    cout<<ans<<endl;

}

signed main(){

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

    sol();

}

D Go Stone Puzzle

传送门

D - Go Stone Puzzle (atcoder.jp)

题意简述:

给你长度为N的串和两个空位(排在串的右侧),每次可以移动两个相邻的石块平移到空位上,问能不能经过有限次的移动将原串转化为新串

思路:

根据数据范围N<=14提示高复杂度算法,再加上询问最小次数,所以考虑BFS。

warning:

一旦字符串下标越界就会变得非常慢!!!

code:

#include<bits/stdc++.h>

#define endl '\n'

#define int long long

using namespace std;

const int MAXN=2e5+10;

struct node{

    string s;

    int opt;

    int kb;

};

int n;

string s,t;

map<string,int>mp;

void sol(){

    cin>>n;

    cin>>s>>t;

    s=s+' '+' ';

    t=t+' '+' ';

    queue<node>q;

    q.push({s,0,});

    while(!q.empty()){

        auto fr=q.front();

        q.pop();

        s=fr.s;

        if(s==t){

            cout<<fr.opt<<endl;

            return ;

        }

        int wr=0;

        for(int i=0;i<n+1;i++){

            if(s[i]==' '){

                wr=i;

                break;

            }

        }

        string str;

        for(int i=0;i<wr-1;i++){

            str=s;

            str[wr]=str[i];

            str[wr+1]=str[i+1];

            str[i]=' ';

            str[i+1]=' ';

            if(mp[str])continue;

            q.push({str,fr.opt+1});

            mp[str]=1;

        }

        for(int i=wr+2;i<n+1;i++){

            str=s;

            str[wr]=str[i];

            str[wr+1]=str[i+1];

            str[i]=' ';

            str[i+1]=' ';

            if(mp[str])continue;

            q.push({str,fr.opt+1});

            mp[str]=1;

        }

    }

    cout<<-1<<endl;

}

signed main(){

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

    sol();

}

E - Tree and Hamilton Path 2

传送门:

E - Tree and Hamilton Path 2 (atcoder.jp)

题意简述:

给你一棵树,问从任意起点开始,最小的从一个点出发,经过所有点的路径的长度

思路:

很显然对于每一个分支需要一去一回走两次,除了从起点到终点的路只需要走一次。所以我们需要找到最大的从起点到终点的路径——即树的直径。

code:

#include<bits/stdc++.h>

#define endl '\n'

#define int long long

using namespace std;

const int MAXN=2e5+10;

#define f first

#define s second

vector<pair<int,int> >e[MAXN];

int n,ans;

int dp[MAXN];

void dfs(int u,int fa,int ww){

    for(auto i:e[u]){

        int v=i.f,w=i.s;

        if(v==fa)continue;

        dfs(v,u,w);

        ans=max(ans,dp[u]+dp[v]);

        dp[u]=max(dp[v],dp[u]);

    }

    dp[u]+=ww;

}

void sol(){

    int tot=0;

    cin>>n;

    int u,v,w;

    for(int i=1;i<n;i++){

        cin>>u>>v>>w;

        e[u].push_back({v,w});

        e[v].push_back({u,w});

        tot+=w;

    }

    dfs(1,0,0);

    cout<<tot*2-ans<<endl;

}

signed main(){

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

    sol();

}

F - x = a^b

传送门:

F - x = a^b (atcoder.jp)

题意简述:

给定N,问1-N中有多少个数可以表示为a的b次方(b>1)的形式。

思路:

因为N的范围是1e18,所以当b=2的时候最大的a为1e9,很显然这个复杂度是不能接受的,但是根据常识我们可以知道当一个数的平方小于n的时候,所有比这个数小的数的平方都将比n小,因此通过sqrt()函数我们可以O(1)的求出。
接着考虑b>2,此时最大的a为1e6,于是我们可以遍历一遍a,同时统计每个a的次方。(注意标vis数组,避免重复计算)
由于4的次幂一定都是2的次幂,所以一旦我们更新次幂的时候发现已经被更小的标记过了,那么就可以直接break掉。
由于部分数可能既是一个数的平方又是一部分数的高次幂,所以我们需要在筛除的时候判断一下是不是一个平方数,最后再进行一下简单容斥

code:

#include<bits/stdc++.h>

using namespace std;

#define int long long

map<int,int>vis;

void sol(){

    int n;

    cin>>n;

    int ans=0,tot=0;

    for(int i=2;i*i*i<=n;i++){

        int res=i*i;

        while(res<=n/i){

            res*=i;

            if(vis[res])break;

            ans++;

            vis[res]=1;

            if(((int)sqrtl(res))*((int)sqrtl(res))==res){

                tot++;

            }

        }

    }

    // cerr<<sqrt(n)<<' '<<ans<<' '<<tot<<endl;

    ans=ans+((int)sqrtl(n))-tot;

    cout<<ans<<endl;

}

signed main(){

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

    sol();

}