Zamjena

前言

感觉这是好几个月之前的坑了。现在才填。

Solution

我们用 map 把字符串 hash 一下(应该叫哈希?)。

第一遍时把两边都是字符串的合并在一个并查集里。

第二遍如果两两是字符串或数字就不用讲了。如果是一个数字,一个串就将串所在的并查集的根的权值标记为数字,如果有数字就比较是否相同。

Code

#include <map>
#include <cctype>
#include <cstdio>
#include <iostream>
using namespace std;

const int N = 5e4 + 5;

int n, cnt, f[N << 1], num[N << 1];
map <string, int> s;
string a[N], b[N];

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

void makeSet() {for(int i = 1; i <= (n << 1); ++ i) f[i] = i;}

int findSet(const int x) {return x == f[x] ? x : f[x] = findSet(f[x]);}

void unionSet(const int x, const int y) {
    int u = findSet(x), v = findSet(y);
    if(u != v) f[u] = v;
}

int main() {
    bool ok = 1; int t;
    n = read();
    makeSet();
    for(int i = 1; i <= n; ++ i) {
        cin >> a[i];
        if(! s[a[i]]) s[a[i]] = ++ cnt;
    }
    for(int i = 1; i <= n; ++ i) {
        cin >> b[i];
        if(! s[b[i]]) s[b[i]] = ++ cnt;
    }
    for(int i = 1; i <= n; ++ i) {
        if(isdigit(a[i][0]) || isdigit(b[i][0])) continue;
        unionSet(s[a[i]], s[b[i]]);
    }
    for(int i = 1; i <= n; ++ i) {
        if(! isdigit(a[i][0]) && (! isdigit(b[i][0]))) continue;
        if(isdigit(a[i][0]) && isdigit(b[i][0])) {
            ok = (a[i] == b[i]);
            if(! ok) break;
            else continue;
        }
        if(isdigit(a[i][0])) swap(a[i], b[i]);
        t = 0;
        for(int j = 0, siz = b[i].length(); j < siz; ++ j)
            t = (t << 1) + (t << 3) + (b[i][j] ^ 48);
        findSet(s[a[i]]);
        if(! num[f[s[a[i]]]]) num[f[s[a[i]]]] = t;
        else {
            if(num[f[s[a[i]]]] == t) continue;
            else {ok = 0; break;}
        }
    }
    puts(ok ? "DA" : "NE");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值