Loading

Codeforces Round #805 (Div. 3) A - G

传送门

第一次赛中 AK div3,值得纪念!

赛后发现有很多题想的不是很周到,所以晚发了这么久

A - Round Down the Price

找到一个不大于当前数字的 10 的次幂

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        ll n;
        cin >> n;
        ll now = 1;
        while(now <= n) now *= 10;
        cout << n - (now / 10) << endl;
    }
    return 0;
}

B. Polycarp Writes a String from Memory

强行模拟一下就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int vis[310];

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        string s;
        cin >> s;
        int ans = 1, cnt = 0;
        for(int i='a'; i<='z'; i++) vis[i] = 0;
        for(int i=0; i<s.length(); i++)
        {
            cnt += ++vis[s[i]] == 1;
            if(cnt == 4)
            {
                ans++;
                cnt = 1;
                for(int i='a'; i<='z'; i++) vis[i] = 0;
                vis[s[i]] = 1;
            }
        }
        cout << ans << '\n';
    }
    return 0;
}

C. Train and Queries

记录一下每个站最早出现的位置和最晚出现的位置,就可以判断一个站台 a 后面是否有存在另一个站台 b

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int num[maxn];
map<int, int>l, r;

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n, m;
        scanf("%d%d", &n, &m);
        l.clear();
        r.clear();
        for(int i=1; i<=n; i++) scanf("%d", &num[i]);
        for(int i=1; i<=n; i++)
        {
            r[num[i]] = i;
            if(l.count(num[i]) == 0) l[num[i]] = i;
        }
        while(m--)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            if(l[x] && l[x] < r[y]) printf("YES\n");
            else printf("NO\n");
        }
    }
    
    return 0;
}

D. Not a Cheap String

贪心

从价值最大的往价值最低的开始减

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
pii num[maxn];
int vis[maxn];

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        string s;
        int p, sum = 0;
        cin >> s >> p;
        for(int i=0; i<s.length(); i++)
        {
            vis[i] = 0;
            num[i] = {s[i] - 'a' + 1, i};
            sum += s[i] - 'a' + 1;
        }
        sort(num, num + s.length());
        for(int i=s.length() - 1; sum>p && i>=0; i--)
        {
            sum -= num[i].first;
            vis[num[i].second] = 1;
        }
        for(int i=0; i<s.length(); i++)
            if(vis[i] == 0) cout << s[i];
        cout << "\n";
    }
    
    return 0;
}

E. Split Into Two Sets

着色 或 并查集

首先能观察出一些普遍的性质:

  1. 所有数字出现的次数一定是 2 次

  2. 一个骨牌不能有两个相同的数字

我的代码是着色的方法做的:

假设一个骨牌是在 1 号堆,则与其冲突的(拥有相同数字)骨牌一定是在 2 号堆,模拟一次看看有没有冲突即可

并查集:

显然拥有相同数字的骨牌是可以相互连接的,我们要做的就是将每一堆相互连接的骨牌按数字平均分成两半,因此,如果同一堆里骨牌的数量为奇数,则不能平均分成两半

因此并查集就要做到每一堆里的数量都是偶数的

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
int vis[maxn], num[maxn][2], cnt[maxn];
vector<int>gra[maxn];

bool dfs(int now, int col)
{
    if(vis[now]) return vis[now] == col;
    vis[now] = col;
    bool f = true;
    for(int i=0; f && i<gra[num[now][0]].size(); i++)
    {
        int nex = gra[num[now][0]][i];
        if(nex != now)
            f = dfs(nex, col ^ 1 ^ 2);
    }
    for(int i=0; f && i<gra[num[now][1]].size(); i++)
    {
        int nex = gra[num[now][1]][i];
        if(nex != now)
            f = dfs(nex, col ^ 1 ^ 2);
    }
    return f;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        for(int i=0; i<=n; i++) {vis[i] = cnt[i] = 0; gra[i].clear();}
        int f = 1;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<2; j++)
            {
                scanf("%d", &num[i][j]);
                gra[num[i][j]].push_back(i);
            }
            if(num[i][0] == num[i][1]) f = 0;
        }
        for(int i=1; i<=n; i++) if(gra[i].size() != 2) f = 0;
        for(int i=0; i<n && f; i++)
        {
            if(vis[i] == 0) f = dfs(i, 1);
        }
        if(f) printf("YES\n");
        else printf("NO\n");
    }
    
    return 0;
}

F. Equate Multisets

有两个操作,直接搜索也显然不现实,考虑能否将两个操作转换成为一个

如果向下整除没有发生取整的情况,那么乘法和除法为可逆,因此考虑将 \(a\) 数组中所有的数字向下除,直到变成奇数,只要 \(b\) 能够转化为这个奇数,则说明他可以变成相对应的 \(a\)

向上乘肯定没办法变成奇数,因此我们考虑将所有的 b 向下除,直到碰到一个 \(a_i\) 转化成的奇数为止

赛中我用了排序,后来发现并不需要,如果 \(b_i\)\(b_j\) 都能到达某奇数,那么肯定可以沿着相同的路线继续往下除,因此就没有说谁一定要先到

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll maxm = 2e6 + 10;
const ll inf = 1e17 + 10;
map<int, int>mp;

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        mp.clear();
        for(int i=0; i<n; i++)
        {
            int x;
            scanf("%d", &x);
            while((x & 1) == 0)
                x >>= 1;
            mp[x]++;
        }
        int ans = 0;
        for(int i=0; i<n; i++)
        {
            int x;
            scanf("%d", &x);
            while(x)
            {
                if((x & 1) && mp[x] > 0)
                {
                    mp[x]--;
                    ans++;
                    break;
                }
                x >>= 1;
            }
        }
        if(ans == n) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

G. Passable Paths

LCA

在树上找到形容一条链,只用找到链的两个端点即可,因此这题的初始想法就是找端点

第一个端点:深度最深的地方

第二个端点:离第一个端点最远的那个点

找到两个端点之后,就判断一下其他点是否在这个链上:最快的方法就是判断两个端点到这个点 \(p\) 的距离之和,是不是和链长相等

以上倍增 LCA 实现一下就好了,距离的话直接找到根的距离,也就是深度差,容斥一下算距离就好了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e17 + 10;
vector<int>gra[maxn];
int dep[maxn], fa[maxn][25], pa[maxn];

void dfs(int now, int pre, int d)
{
    dep[now] = d;
    fa[now][0] = pre;
    for(auto nex : gra[now])
    {
        if(nex == pre) continue;
        dfs(nex, now, d + 1);
    }

}

void init(int n, int rt = 1)
{
    dfs(rt, rt, 0);
    for(int i=1; i<=20; i++)
        for(int j=1; j<=n; j++)
            fa[j][i] = fa[fa[j][i-1]][i-1];
}

int LCA(int a, int b)
{
    if(dep[a] < dep[b]) swap(a, b);
    int dif = dep[a] - dep[b];
    for(int i=20; i>=0; i--)
    {
        if(dif >= (1 << i))
        {
            dif -= 1 << i;
            a = fa[a][i];
        }
    }
    if(a == b) return a;
    for(int i=20; i>=0; i--)
    {
        if(fa[a][i] != fa[b][i])
        {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0];
}

int dis(int a, int b)
{
    return dep[a] + dep[b] - 2 * dep[LCA(a, b)];
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1; i<n; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        gra[x].push_back(y);
        gra[y].push_back(x);
    }
    init(n);
    int m;
    scanf("%d", &m);
    while(m--)
    {
        int k;
        scanf("%d", &k);
        int d = -1, a = 0, b = 0, f = 1;
        for(int i=0; i<k; i++)
        {
            scanf("%d", &pa[i]);
            if(dep[pa[i]] > d) {a = pa[i]; d = dep[pa[i]];}
        }
        d = -1;
        for(int i=0; i<k; i++)
        {
            int x = dis(a, pa[i]);
            if(d < x)
            {
                b = pa[i];
                d = x;
            }
        }
        for(int i=0; i<k && f; i++)
        {
            if(dis(a, pa[i]) + dis(b, pa[i]) != d)
                f = 0;
        }
        printf("%s\n", f ? "yes" : "no");
        
    }
    return 0;
}
posted @ 2022-07-13 19:52  dgsvygd  阅读(41)  评论(0编辑  收藏  举报