Atcoder Beginner Contest 285(A - D) 题解

目录

前言

题解

A - Edge Checker 2

题意

题解

代码

B - Longest Uncommon Prefix

题意

题解

代码

C - abc285_brutmhyhiizp

题意

题解

代码

D - Change Usernames

题意

题解1

代码1

题解2

代码2


前言

关于我是一个爱装的人,没事就装。俗话说,装X遭雷劈,ABC285就被雷劈了。

 Atcoder Beginner Contest 285(A - D) 题解_第1张图片

 一个二十分钟的题目做了一个小时,还吃了一发罚时。

废话不多说,进入正题。

题解

A - Edge Checker 2

题意

一棵满二叉树如图所示。

给你a,b,问你a,b是否相连(a > b)

题解

满二叉树有一个性质。

就是节点i的儿子是(2i)和 (2i + 1)

我们利用c++正常除法向下取整这个特点,得出:如果b / a == 2 那么输出“Yes”,否则输出“No”

因为如果b是2a+1,在c++中,直接除可以向下取整,所以,b \div a = (2a + 1) \div a

如果b是2a,b \div a = 2a \div a,

其余情况都不相连。

代码

#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template 
int rets(T x) {cout << x << endl; return 0;}
string s;
void init(){
    
}
signed main(){
    init();
    cin >> n >> m;
    if (m / 2 == n) cout << "Yes" << endl; 
    else cout << "No" << endl; 
    return 0;
}

B - Longest Uncommon Prefix

其实这题很简单,但是读题是个问题,否则我也不可能16min才A掉。

题意

给你一个字符串,长度为n。

枚举l使得,s[i + l] < n 并且 s_i \neq s_{i + l}

题解

按题意模拟就行。

代码

#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define mod 998244353
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template 
int rets(T x) {cout << x << endl; return 0;}
char s[M];
void init(){
    
}
signed main(){
    init();
    cin >> n >> (s + 1);
    for (int l = 1 ; l < n ; l ++) {
        int ans = 0;
        for (int i = 1 ; i + l <= n ; i ++) {
            if (s[i] == s[i + l]) break;
            ans = i;
        }
        cout << ans << endl; 
    }
    return 0;
}

C - abc285_brutmhyhiizp

题意

在atcoder王国里,有10^{16}个问题,每个问题都编号依次为A,B,C……AA,AB,……,ZZ……

然后给你一个字符串,请问这是第几个问题。

题解

如AAABB

设pro[i]表示从1到i的这个字符串的编号,例如:pro[2] = "AA"的编号。

观察发现

pro[1] = (s[0] - 'A' + 1) * 26^{0} =  26^{0}

 pro[2] = pro[1] * 26 + (s[1] - 'A' + 1) = 26^1 + 1 = 27

pro[3] = pro[2] * 26 + (s[2] - 'A' + 1) …… 以此类推。

所以,pro[i] = pro[i - 1] * 26 + (s[i - 1] - 'A' + 1)

但是,这里我们优化一下空间,倒着计算,类似于哈希。

// 伪代码
base = 1;
for i : s.size() - 1 to 0 then do
    ans += (s[i] - 'A' + 1) * base;
    base *= 26;

代码

#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define mod 998244353
#define all(s) s.begin(),s.end()
#define Mn(a,b,c) min(a,min(b,c))
#define Mx(a,b,c) max(a,max(b,c))
#define sq(x) ((x) * (x))
#define cub(x) ((x) * (x) * (x))
#define all(s) s.begin(),s.end()
#define e9 1000000000
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template 
int rets(T x) {cout << x << endl; return 0;}
string s;
void init(){
    
}
signed main(){
    init();
    cin >> s;
    int ans = 0 , base = 1;
    for (int i = s.size() - 1 ; i >= 0 ; i --) {
        ans += (s[i] - 'A' + 1) * base;
        base *= 26;
    }
    cout << ans << endl; 
    return 0;
}

D - Change Usernames

就是这道题!!!装X遭雷劈

题意

有n个用户。每个用户都想改自己的名字从s_i改成t_i(吃饱了撑着没事干)

  • 你每次只能改一个用户的名字
  • 你每次也只能把一个用户的名字改一次
  • 名字不能重复

问你能不能在满足上面三个条件的情况下,把所有用户的名字改成他们想要的。

能输出“Yes”,否则输出“No”

题解1

乍一眼看,好像这是一道暴力改名字的题目,但是那样就会很复杂。

思考一下,

a 把名字改成 b     ,   b 把名字改成 c

如果c把名字改成不是a或b的就可以了

a -> b ,b -> c  

c不能-> a,也不能 -> b

这不是个有向图判环吗!

不会有向图判环的点这里,题解2.

设a把名字改成b就是a到b有一条单向边,如果存在环,那么在改的时候就会重复。

举个例子:

a -> b
b -> c
c -> d
d -> a

当,你把a改成b时,你会发现,重复了。所以在这之前,你必须把b改成c,又重复了,在此之前,你必须把c改成d,重复,在此之前,你必须把d改成a。完了,人麻了,死循环。

所以只要有环,就判“No”。

上代码!

代码1

#include 
using namespace std;
#define int long long 
#define endl "\n"
const int N = 2e5 + 5;
int n,k = 1;
vector G[N];
map mp;
int vis[N], ind[N];
queue Q;
int BFS() {
    while (!Q.empty()) Q.pop();
    for (int i = 1;i <= k-1; i++) if(ind[i] == 0) Q.push(i);
    int cnt = Q.size();
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for(int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            ind[v] --;
            if(ind[v] == 0) {
                Q.push(v);
                cnt++;
            } 
        }
    }
    return cnt;
}

signed main() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        string u,v;
        cin >> u >> v;
        if (!mp[u]) mp[u] = k ++;
        if (!mp[v]) mp[v] = k ++;
        G[mp[u]].push_back(mp[v]);
        ind[mp[v]]++;
    }
    cout << (BFS() == k - 1 ? "Yes" : "No") << endl; 
    return 0;
}

题解2

但是有的大佬不会有向图判环咋整?

Atcoder Beginner Contest 285(A - D) 题解_第2张图片

别急,办法总是有的(就是因为这个,所以我才没用有向图判环,否则我20min就AC了。) 

先假设这个图不全是环,那么他总是有一个名字不会被改。找到这个名字,开始我们的

DFS之旅!!!(不就是DFS,有什么好大惊小怪的)

首先,用vector存图,记录下每个人要改的名字,找到不改的名字,DFS。

DFS里面,如果这个名字被访问过,直接return false。

如果这个名字不会改,return true。

然后return DFS(他要改的名字)。

写完了,交一发!

AC!

oj表示:WA!你得意个啥。

Atcoder Beginner Contest 285(A - D) 题解_第3张图片

 

Atcoder Beginner Contest 285(A - D) 题解_第4张图片

为什么WA?

看到我们的条件没有? 

那全是环呢?

当然随便找一个点就可以DFS了,验证一下就行了,反正都是false 

再交一发!

AC!

OJ表示:,你已经吃两发罚时了!

为什么?为什么?上帝为什么这么要对待我!

这是一个疯子,我们不要理会他。

会不会有一种情况,他不是一个连通图。

唉,所以要从vis没有标记过的点开始遍历。

再交一发!

 上帝保佑我AC。

 OJ表示: ,我跪了,求你了,别交了,我会炸的。

嘿嘿,我就要把你交炸。

这真是个一本正经(sàng xīn bìng kuáng)的人。

还是那个问题:为什么会WA?

深入思考,你会发现连样例3你都过不去。为什么?

你有没有发现,你遍历的时候,如果,一个字符串遍历过了,会return false,

但是,如果你先从它开始,然后再有人想把他的名字改成这个字符串,就会return false,所以,我们要标记一下,计作vis2,如果vis2没有标记过,再遍历。

终于可以上AC Code了。

代码2

#include
using namespace std;
#define ll long long
#define MAXN 1048586
#define M 5005
#define N 500005
#define lowbit(x) ((x)&(-(x)))
#define int long long
#define endl "\n"
#define _clear(q) while (!q.empty()){q.pop();}
int n,m,k;
template 
int rets(T x) {cout << x << endl; return 0;}
string s;
struct Node {
    string from,to;
}a[N];
map  vis;
map  vis1;
map  > fa;
vector  fir;
map  vis2;
void init(){
    
}
bool DFS (string s) {
    // cout << s << endl; 
    if (vis[s]) {return false;}
    if (fa[s].size() == 0) return true;
    vis[s] = 1;
    return DFS(fa[s][0]);
}
signed main(){
    init();
    cin >> n;
    for (int i = 1 ; i <= n ;i ++) {
        cin >> a[i].from >> a[i].to;
        vis2[a[i].to] = 1;
        // cout << a[i].from << " " << a[i].to << endl; 
        fa[a[i].from].push_back(a[i].to);
        // cout << a[i].from << " " << fa[a[i].from] << endl;
    }
    for (int i = 1 ; i <= n ;i ++) {
        if (!vis[a[i].from] && !vis2[a[i].from]) {
            // cout << i << endl; 
            bool t = DFS(a[i].from);
            if (!t) return rets("No");
        }
    }
    for (int i = 1 ; i <= n ;i ++) {
        if (!vis[a[i].from]) {
            // cout << i << endl; 
            bool t = DFS(a[i].from);
            if (!t) return rets("No");
        }
    }
    rets("Yes");
    return 0;
}

你可能感兴趣的:(c,++,算法)