AtCoder Beginner Contest 244

目录

A - Last Letter

 B - Go Straight and Turn Right

 C - Yamanote Line Game 

 D - Swap Hats

 E - King Bombee

F - Shortest Good Path


A - Last Letter

  • 题意

 给定一个字符串输出最后一个字符

  •  思路:

语法题,见代码

  • 时间复杂度 :

O(n)

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 2e5+10,M = N * 2,INF = 0x3f3f3f3f,P = 9901;


int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n;
    std::string s;
    std::cin>>n>>s;
    std::cout<<s[n-1];
    return 0;
}

 B - Go Straight and Turn Right

  • 题意

小明在开始时站在(0,0)点

现给定一个字符串S,小明会根据字符串中的字母,按顺序执行操作:

  1. 若为'S',小明向前前进一个单位
  2. 若为'R',小明的朝向顺时针转动90度
  •  思路:

模拟即可

  • 时间复杂度 :

O(n)

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 2e5+10,M = N * 2,INF = 0x3f3f3f3f,P = 9901;


int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n,ne[4][2] = {1,0,0,-1,-1,0,0,1};
    int state = 0,x = 0,y = 0;
    std::string s;
    std::cin>>n>>s;
    for(int i = 0 ; i < n ; i++)
    {
        if(s[i]=='S')
        {
            x += ne[state][0];
            y += ne[state][1];
        }
        else
        {
            state++;
            if(state==4)state = 0;
        }
    }
    std::cout<<x<<" "<<y;
    return 0;
}

 C - Yamanote Line Game 

  • 题意

本题交互题:

规则:

给定一个数n,双方需要在1 ~( 2 * n + 1 )中选择一个数打印,之前打印过的数不能够再打印,直至其中一方找不到打印数为止。

  •  思路:

用一个set存下所以可以打印的数,每次打印完就把这个数从set中删除,我们输出时,每次输出这个set的最小数即可。

  • 时间复杂度 :

O(nlogn)

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 2e5+10,M = N * 2,INF = 0x3f3f3f3f,P = 9901;

int query()
{
    int x;
    std::cin>>x;
    return x;
}

void solve()
{
    int n;
    std::cin>>n;
    std::set<int> st;
    for(int i = 1 ; i <= 2 * n + 1; i++)st.insert(i);
    while(true)
    {
        std::cout<<*st.begin()<<std::endl;
        st.erase(st.begin());
        int x = query();
        if(x==0)break;
        st.erase(x);
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
//    int T;
//    std::cin>>T;
//    while(T--)
    {
        solve();
    }
    return 0;
}

 D - Swap Hats

  • 题意

给三个人分别戴上三顶帽子,这三顶帽子为R B G。

初始时给定这三人戴帽子的情况,并给定三个人最终的戴帽子的情况。

现在可以交换两个人戴的帽子,执行 这个操作  10^{18}  次。

询问是否可以将初始状态变为最终状态。

  •  思路:

显然不能模拟,我们可以讨论交换次数的奇偶性

存在三种情况:

  1. 初始状态和最终状态相同,那么可以通过不断交换1,2两个人的帽子保持偶数次操作时状态不变。(所以操作次数为偶数)
  2. 有两顶帽子不同,那么可以交换这两顶帽子,然后重复情况1。(操作次数为奇数)
  3. 有三顶帽子不同,那么可以两次操作变成情况1,重复1即可(操作次数为偶数)

操作次数为奇数,显然是"NO"

操作次数为偶数,显然是"YES"

  • 时间复杂度 :

O(1)

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 2e5+10,M = N * 2,INF = 0x3f3f3f3f,P = 9901;


void solve()
{
    char s[3],t[3];
    for(int i = 0 ; i < 3 ; i++)std::cin>>s[i];
    for(int i = 0 ; i < 3 ; i++)std::cin>>t[i];
    int cnt = 0;
    for(int i = 0 ; i < 3 ; i++)if(s[i]!=t[i])cnt++;
    if(cnt==2)std::cout<<"No";
    else std::cout<<"Yes";
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
//    int T;
//    std::cin>>T;
//    while(T--)
    {
        solve();
    }
    return 0;
}

 E - King Bombee

  • 题意

给定一个无向图

求起点为S,终点为T,经过点数为K+1,其中点X的个数为偶数(可以为0)的路径数

  •  思路:

我们尝试动态规划:

设   dp[i][j][k] :

  1. dp的值是方案数
  2. i 表示的是当前已经经过的点数
  3. 表示的是当前路径的最后一个点是 j
  4. 表示的是这个路径中经过X次数的奇偶性(0为偶数,1为奇数)

那么初始状态为dp[1][S][0] = 1

答案为 dp[k+1][T][0]

状态转移为( u 为 j 相邻的点):

u == x:

dp[i][j][0] = dp[i][j][0] + dp[i-1][u][1]

dp[i][j][1] = dp[i][j][1] + dp[i-1][u][0]

u != x:

dp[i][j][0] = dp[i][j][0] + dp[i-1][u][0]

dp[i][j][1] = dp[i][j][1] + dp[i-1][u][1]

  • 时间复杂度 :

要转移 i 次,每次转移都要遍历所有的边。

O(km)

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 2e3+10,M = N * 2,INF = 0x3f3f3f3f,mod = 998244353;

int dp[N][N][2];
int h[N],e[M],ne[M],idx;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    memset(h,-1,sizeof h);
    int n,m,k,S,T,x;
    std::cin>>n>>m>>k>>S>>T>>x;
    while(m--)
    {
        int a,b;
        std::cin>>a>>b;
        add(a,b),add(b,a);
    }
    dp[1][S][0] = 1;
    for(int i = 2 ; i <= k + 1 ; i++)
    {
        for(int j = 1 ; j <= n ; j++)
        {
            if(dp[i-1][j][0]||dp[i-1][j][1])
            {
                for(int o = h[j] ; ~o ; o = ne[o])
                {
                    int u = e[o];
                    if(u==x)
                    {
                        dp[i][u][0] = (dp[i][u][0] + dp[i-1][j][1]) % mod;
                        dp[i][u][1] = (dp[i][u][1] + dp[i-1][j][0]) % mod;
                    }
                    else
                    {
                        dp[i][u][0] = (dp[i][u][0] + dp[i-1][j][0]) % mod;
                        dp[i][u][1] = (dp[i][u][1] + dp[i-1][j][1]) % mod;
                    }
                }
            }
        }
    }
    std::cout<<dp[k+1][T][0];
    return 0;
}

F - Shortest Good Path

  • 题意

对于某个边权均为 1 的无向图,给定所有只含有0和1的长度为n的字符串

对于某一个字符串,我们要寻找这样一条路径:

若  S_{i} = 1 ,则点 i 出现的次数应该为奇数

若  S_{i} = 0 , 则点 i 出现的次数应该为偶数(可以为0)

对于某一种情况的字符串,计算这个路径的长度最小值

求出所有路径的和

  •  思路:

有题目所给范围以及信息已知本题需要用状态压缩

设 dp[i][j]:

  1. dp值为路径最小长度
  2. i  表示状态,第 k 位为0则代表点 k 出现次数为偶数,反之为奇数
  3. j 表示当前状态下当前所在点为 j

那么显然,所有点出现次数为偶数时,路径长最小值为0

当只有某个点出现次数为奇数时,路径最小长度为1

我们可以这些点为出发点,使用BFS,得到所有情况的最小值

答案可以表示为:

\sum_{i = 1}^{(1\ll n)-1}min(\sum_{j = 1}^{n}dp[i][j])

  • 时间复杂度 :

因为是通过枚举邻边进行拓展,所以时间复杂度要乘m

O(nm2^{n})

AC代码:

#include<bits/stdc++.h>

typedef long long ll;
typedef unsigned long long ull;

const int N = 19,M = N * N,INF = 0x3f3f3f3f,mod = 998244353;
struct Node{
    int state,u;
}que[(1<<N)*N];
int dp[1<<N][N];
int tail,head;
int h[N],e[M],ne[M],idx;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n,m;
    head = 0,tail = -1;
    memset(h,-1,sizeof h);
    memset(dp,0x3f,sizeof dp);
    std::cin>>n>>m;
    while(m--)
    {
        int a,b;
        std::cin>>a>>b;
        add(a,b),add(b,a);
    }
    dp[0][1] = 0;
    for(int i = 0 ; i < n ; i++)
    {
        dp[1<<i][i+1] = 1;
        que[++tail] = {1<<i,i+1};
    }
    while(tail>=head)
    {
        auto temp = que[head++];
        for(int i = h[temp.u] ; ~i ; i = ne[i])
        {
            int u = e[i];
            int state = temp.state ^ (1 << (u-1));
            if(dp[state][u]==INF)
            {
                dp[state][u] = dp[temp.state][temp.u] + 1;
                que[++tail] = {state,u};
            }
        }
    }
    int res = 0;
    for(int i = 0 ; i < (1 << n) ; i++)
    {
        res += *std::min_element(dp[i]+1,dp[i]+n+1);
//        std::cout<<*std::min_element(dp[i]+1,dp[i]+n+1)<<'\n';
    }
    std::cout<<res;
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值