AtCoder ABC 243题解

AtCoder ABC 243

A Shampoo(水)

Description:

​ 三个人轮流用水 请问用到谁的时候水就用完了

Method:

​ 水题 但是因为%和/用错了 导致蛙了好几次

​ 分类讨论 如果一轮用不完 就取余再判断 如果一轮用得完 直接判断

Code:

void solve()
{
	int v, a, b, c;
    cin >> v >> a >> b >> c;
    int sum = a + b + c;
    int t =  v % sum;
    if(sum > v)  
    {
        if(a > v)   {cout << "F"; return;}
        else if(a + b > v)  {cout << "M"; return;}
        else {cout << "T"; return;}
    }  
    else
    {
        if(a > t)   {cout << "F"; return;}
        else if(a + b > t)  {cout << "M"; return;}
        else {cout << "T"; return;}
    }
}

B Hit and Blow(水)

Description:

​ 给定两个数组a b 判断数组中位置和数值都相同的个数 & 位置不同数值相同的个数

Method:

​ map查重咯

Code:

void solve()
{
	int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
 
    for(int i = 1; i <= n; i++)
        cin >> b[i];
 
    int res1 = 0, res2 = 0;
    for(int i = 1; i <= n; i++)
        mp[a[i]] = true;
    for(int i = 1; i <= n; i++)
        if(mp[b[i]])    res2 ++;
    for(int i = 1; i <= n; i++)
        if(a[i] == b[i])    res2 --, res1 ++;
    cout << res1 << '\n' << res2;
}

C Collision 2(水)

Description:

​ 给出n个点的坐标和行进方向 若是两个坐标会相遇 输出yes

Method:

​ 显然 判断yes更简单 我们进行排序 然后对相同纵坐标进行判断 若是左边的点向右走 右边的点向左走 YES

Code:

struct node 
{
    int x, y, op; // op 0 L  op 1 R
    bool operator< (const node & E) const 
    {
        if(y == E.y)    return x < E.x;
        return y < E.y;
    }
}q[200010];
 
void solve()
{
	int n;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> q[i].x >> q[i].y;
    
    string s;
    cin >> s;
    for(int i = 0; i < n; i++)
    {
        if(s[i] == 'L') q[i].op = 0;
        else q[i].op = 1;
    }
 
    sort(q, q + n);
    for(int i = 1; i < n; i++)
    {
        if(q[i].y != q[i - 1].y)    continue;
        if(q[i - 1].op == 1 && q[i].op == 0) 
        {
            puts("Yes"); return;
        }
    }
    puts("No");
}

D Moves on Binary Tree(二叉树)

Description:

​ 给出当前节点 对节点进行一个1e6的操作 每次操作选择移动到他的父节点 左儿子 或者右儿子

​ 节点数会在longlong的极限左右 但保证最终答案一定在longlong范围内

Method:

​ 因为给的节点数字很大 用高精度模拟会TLE 正常模拟会爆long

​ 我的猜想就是消除题目中的U 和 L 但是经验证不对

​ 因为R是 x * 2 + 1 而U是 x / 2 这一点就带来了误差

1 消除相邻的UL 和 RL 因为R仅仅是加了一次1 这时直接除2并不会造成影响 且保证答案在LL内

2 将节点化为二进制串表示并进行二进制的计算 然后再转回十进制

Code:

stack<char> stk;

void solve()
{
    int n;
    LL x;
    cin >> n >> x;
    string s;
    cin >> s;
    int l, r;
    for(int i = 0; i < n; i++)
    {
        if(!stk.empty())  
        {
            if((s[i] == 'U' && (stk.top() == 'L' || stk.top() == 'R'))) stk.pop();
            else    stk.push(s[i]);
        }
        else stk.push(s[i]);
    }
    string res;
    while(stk.size())   res += stk.top(), stk.pop();
    reverse(res.begin(), res.end());
    for(int i = 0; i < res.size(); i++)
    {
        if(res[i] == 'L')       x *= 2;
        else if(res[i] == 'R')  x = x * 2 + 1;
        else                    x /= 2;
    }
    cout << x << '\n';
}
string get_(LL x)//十转二
{
    string res;
    while(x)
    {
        res += '0' + (x % 2);
        x /= 2;
    }
    reverse(res.begin(), res.end());
    return res;
}

void solve()
{
    int n; LL x;
    cin >> n >> x;
    string s;
    cin >> s;
    string nums = get_(x);
    for(int i = 0; i < n; i++)
    {
        if(s[i] == 'R')     nums += '1';
        else if(s[i] == 'L')    nums += '0';
        else    nums.erase(nums.end() - 1);
    }
    int m = nums.size();
    LL res = 0;
    reverse(nums.begin(), nums.end());
    for(int i = 0; i < m; i++)//二转十
    {
        LL t = nums[i] - '0';
        res += t * (1LL << i);
    }
    cout << res << '\n';
}

E Edge Deletion(图论 + 构造)

Description:

​ 给定n个顶点m条边 保证不会出现重边和自环

​ 请尝试删去最多的边(在不影响原有两点之间路径长度以及保持图的联通)

Method:

​ 原有两点路径看起来很复杂 其实就是对最短路查重 若是如样例一一般 最短路有两条 且权相同 可以删去

​ 我们先通过flody跑一遍最短路 然后遍历两个顶点和中转点询问是否存在最短路重复

Code:

int n, m;// point n  edge m
int a, b;
LL c;
LL mp[310][310];

void solve()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            mp[i][j] = (i == j) ? 0 : INF;

    for(int i = 0; i < m; i++)
    {
        cin >> a >> b >> c;
        mp[a][b] = c;
        mp[b][a] = c;
    }

    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]);
    
    int res = 0; //保留的边数
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(i != j)
            {
                int rem = 1;
                for(int k = 1; k <= n; k++) 
                    if(i != k && j != k && mp[i][j] == mp[i][k] + mp[k][j]) 
                    //存在这种情况的时候 可以去掉一个边
                        rem = 0;
                res += rem;
            }
    cout << m - res / 2 << '\n'; //因为正反都扫了一遍 所以保留的边数/2
}

F Lottery(不会)

Description:

Method:

Code:

G Sqrt(DP + 前缀和 + 优化)

Description:

Method:

​ 尽力去听了 但是还是不懂 放一串代码吧

Code:

#include <bits/stdc++.h>

using namespace std;
//多组输入的初始化 
//判断是否需要LL

#define ios ios::sync_with_stdio(false);cin.tie(0);
#define endl '\n'
#define ms(x, y)    memset(x, y, sizeof x)
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1000010;
LL dp[N], pre[N];

LL is_sqrt(LL x)
{
    LL sqrtX = sqrt(x) - 1;
    while(sqrtX + 1 <= x / (sqrtX + 1)) sqrtX ++;
    return sqrtX;
}

void solve() 
{
    cin >> x;
    LL x2 = is_sqrt(x);
    LL x4 = is_sqrt(x2);
    LL res = 0;
    for(int i = 1; i <= x4; i++)
        res += (x2 - 1LL * i * i + 1) * dp[i];
    cout << res << '\n';
}


int main()
{
    ios;
    dp[1] = 1;
    pre[1] = 1;
    for(int i = 2; i <= N; i++)
        dp[i] = pre[is_sqrt(i)], pre[i] = pre[i - 1] + dp[i];
    
	int _;
    cin >> _;
    while(_--)  solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值