AtCoder Beginner Contest 309 (A~E)

A - Nine

题意:给一个3*3的方格,给A和B两个数,问是否水平相邻。

思路:直接模拟

#include<bits/stdc++.h>

using namespace std;

const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;



int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int a,b;
    cin >> a >> b;
    int mn = min(a,b), mx = max(a,b);
    int f = 0;
    if(mn == 1 && mx == 2) f = 1;
    else if(mn == 2 && mx == 3) f = 1;
    else if(mn == 4 && mx == 5) f = 1;
    else if(mn == 5 && mx == 6) f = 1;
    else if(mn == 7 && mx == 8) f = 1;
    else if(mn == 8 && mx == 9) f = 1;
    cout << (f ? "Yes" : "No");
    return 0;
}

B - Rotate

题意:给一个二维数组a,对它最外一层进行顺时针旋转移动一格。输出移动后的二维数组。

思路:我用两个二维数组,进行模拟。

#include<bits/stdc++.h>

using namespace std;

const int N = 100010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;

int a[110][110], b[110][110];

int main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++ )
        for(int j = 1; j <= n; j ++ )
        {
            scanf("%1d", &a[i][j]);
            b[i][j] = a[i][j];
        }
    
    // a[1][1] = b[2][1];
    //上面一层向右移
    for(int i = 1; i <= n; i ++ ) 
        a[1][i + 1] = b[1][i];
    //右边一层向下移
    for(int i = 1; i <= n; i ++ )
        a[i + 1][n] = b[i][n];
    for(int i = 1; i <= n - 1; i ++ )
        a[n][i] = b[n][i + 1];
    //下面一层向左移
    for(int i = 1; i <= n - 1; i ++ )
        a[i][1] = b[i + 1][1];
    //左边一层向上移
    for(int i = 1; i <= n; i ++ )   
    {
        for(int j = 1; j <= n; j ++ )
            cout << a[i][j];
        cout << '\n';
    }
    return 0;
}

C - Medicine

题意:有n中不同的药要吃,某一种药连续a_i天吃b_i片,问最早哪一天吃的药的数量小于等于k片。

思路:假设最后吃到p天,画图可以看出1~p吃药的数量是单调不递增的,那么二分天数,如果这天吃的药小于等于k片向左找,否则向右找。

#include<bits/stdc++.h>

using namespace std;

const int N = 300010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;
ll n, k;
ll a[N],b[N];
bool check(ll x)
{
    ll sum = 0;
    for(int i = 1; i <= n; i ++ )
        if(a[i] >= x) sum += b[i];
    return sum <= k;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> k;
    for(int i = 1; i <= n; i ++ ) cin >> a[i] >> b[i];
    ll l = 1, r = 1e10;
    while(l < r)
    {
        ll mid = (l + r) >> 1;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << '\n';
    return 0;
}

D - Add One Edge

题意:1~N_1的点互相连通,N_1~N_1+N_2的点互相连通,问加一条边,求1到N_1+N_2的最短距离为d,我们要使d尽可能的大。

思路:对于点1,N_1+N_2分别跑bfs,并记录各自的到某个点的最大值a,b,加一条到这两个点,那么使d不就最大了,答案a+b+1。

题解:

#include<bits/stdc++.h>

using namespace std;

const int N = 300010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;

vector<int> g[N];
// int l[N], r[N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int a, b, m;
    cin >> a >> b >> m;
    for(int i = 0; i < m; i ++ )
    {
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }

    queue<pii> q;
    vector<int> v(a + b + 10);
    v[1] = 1;
    q.push({1, 0});
    int lmx = 0, rmx = 0;
    while(q.size())
    {
        auto t = q.front(); q.pop();
        int p = t.first, d = t.second;
        lmx = max(lmx, d);
        for(int i = 0; i < g[p].size(); i ++ )
        {
            int j = g[p][i];
            if(!v[j])
            {
                v[j] = 1;
                q.push({j, d + 1});
            }
        }
    }
    for(auto i : v) i = 0; 
    v[a + b] = 1;
    q.push({a+b, 0});
    while(q.size())
    {
        auto t = q.front(); q.pop();
        int p = t.first, d = t.second;
        rmx = max(rmx, d);
        for(int i = 0; i < g[p].size(); i ++ )
        {
            int j = g[p][i];
            if(!v[j])
            {
                v[j] = 1;
                q.push({j, d + 1});
            }
        }
    }
    // cout << lmx << ' ' << rmx << endl;
    cout << lmx + rmx + 1 << '\n';
    return 0;
}

E - Family and Insurance

题意:一棵树,父节点x买了保险对于y后代都覆盖有保险,问至少多少人有一份保险。

思路:刚开始是想的给一个操作去dfs一次,但是会超时,就一直想怎么优化。对于每个人只要有买或受到保险覆盖即可,将所有操作y_i后代拿一个数组p保存,对每一个节点去dfs,并用vis数组记录是否访问,对于当前节点u对后代产生保x,设cnt为从父节点对后代的影响,x = max(cnt, p[u]),保证每个节点只会访问一次。

代码:

#include<bits/stdc++.h>

using namespace std;

const int N = 300010, mod = 1e9 + 7;
typedef long long ll;
typedef pair<int,int> pii;

int n, m;
vector<int> g[N];
int p[N];
int ans;
int v[N];

void dfs(int u, int cnt)
{
    int cur = max(cnt, p[u]);
    v[u] = 1;
    if(cur >= 0) ans++;
    else return ;
    for(int i = 0; i < g[u].size(); i ++ )
    {
        int j = g[u][i];
        if(!v[j])
        {
            dfs(j, cur - 1);
        }
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n >> m;
    for(int i = 2; i <= n; i ++ )
    {
        int x;
        cin >> x;
        g[x].push_back(i);
    }
    memset(p, -1, sizeof p);
    for(int i = 0; i < m; i ++ )
    {
        int x,y;
        cin >> x >> y;
        p[x] = max(y, p[x]);
    }
    for(int i = 1; i <= n; i ++ ) 
        if(!v[i]) dfs(i, p[i]);
    
    cout << ans << '\n';
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值