NOIP2023模拟12联测33 D. 滈葕

NOIP2023模拟12联测33 D. 滈葕

题目大意

231101_5PtkSBXNaX.png (654×896) (hszxoj.com)

思路

放一段题解的材料

ABO 血型系统是血型系统的一种,把血液分为 A,B,AB,O 四种血型。血液由红细胞和血清等组成,红细胞表面 有凝集原,血清内有凝集素。根据红细胞表面有无凝集原 A 和 B 来划分血液类型。红细胞上只有凝集原 A 的 为 A 型血,其血清中有抗 B 凝集素;红细胞上只有凝集原 B 的为 B 型血,其血清中有抗 A 凝集素;红细胞上 两种凝集原都有的为 AB 型血,其血清中无凝集素;红细胞上两种凝集原皆无者为 O 型,其血清中两种凝集素 皆有。有凝集原 A 的红细胞可被抗 A 凝集素凝集;有凝集原 B 的红细胞可被抗 B 凝集素凝集。配血试验是两 个人分别提供红细胞和血清并将其混合,观察是否有凝集反应。

可以发现,ABCD 的属性分别表示 A,B,AB,O 型血,一条边表示一次配血试验

设一条边 ( u , v , w ) (u , v , w) (u,v,w)

w = 0 w = 0 w=0 则:KaTeX parse error: Undefined control sequence: \and at position 10: \neg(a_u \̲a̲n̲d̲ ̲a_v) \and \neg …

w = 1 w = 1 w=1 则:KaTeX parse error: Undefined control sequence: \and at position 6: (a_u \̲a̲n̲d̲ ̲\neg a_v) \or (…

可以用 2 − S A T 2-SAT 2SAT 来处理

编号为:
a i , i ¬ a i i + n b i , i + n ∗ 2 ¬ b i , i + n ∗ 3 a_i , i \newline \neg a_i i +n \newline b_i , i +n *2 \newline \neg b_i , i +n *3 ai,i¬aii+nbi,i+n2¬bi,i+n3

数组开大点

code

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
using namespace std;
const int N = 1e5 + 5;
int a[N << 2] , a1 , n , m , hd[N << 2] , low[N << 2] , dfn[N << 2] , cnt , p1 , p2 , num[N << 2];
stack<int> stk;
struct E {
    int to , nt;
} e[N << 6];
void add (int x , int y) { e[++cnt].to = y , e[cnt].nt = hd[x] , hd[x] = cnt; }
void dfs (int x , int fa) {
    stk.push(x);
    int y;
    dfn[x] = low[x] = ++p1;
    for (int i = hd[x] ; i ; i = e[i].nt) {
        y = e[i].to;
        if (!dfn[y]) {
            dfs (y , x);
            low[x] = min (low[x] , low[y]);
        }
        else if (!num[y]) {
            low[x] = min (low[x] , dfn[y]);         
        }
    }
    if (dfn[x] == low[x]) {
        p2 ++;
        y = 0;
        while (y != x && !stk.empty()) {
            y = stk.top();
            stk.pop();
            num[y] = p2;
        }
    }
}
int main () {
    freopen ("dopetobly.in" , "r" , stdin);
    freopen ("dopetobly.out" , "w" , stdout);
    int u , v , w;
    scanf ("%d%d" , &n , &m);
    fu (i , 1 , m) {
        scanf ("%d%d%d" , &u , &v , &w);
        if (!w) {
            add (u , v);
            add (v + n , u + n);
            add (u + n * 2 , v + n * 2);
            add (v + n * 3 , u + n * 3);
        }
        else {
            add (u + n , u + n * 2);
            add (u + n , v + n * 3);
            add (u + n * 3 , u);
            add (u + n * 3 , v + n);
            add (v , u + n * 2);
            add (v , v + n * 3);
            add (v + n * 2 , u);
            add (v + n * 2 , v + n);
        }
    }
    fu (i , 1 , n * 4) {
        if (!dfn[i]) {
            dfs (i , 0);
        }
    }
    fu (i , 1 , n) {
        if (num[i] == num[i + n] || num[i + n * 2] == num[i + n * 3]) {
            puts ("NO");
            exit (0);
        }
    }
    puts ("YES");
    fu (i , 1 , n) {
        bool x = num[i] < num[i + n] , y = num[i + n * 2] < num[i + n * 3];
        if (x && !y) printf ("A");
        else if (!x && y) printf ("B");
        else if (x && y) printf ("C");
        else printf ("D");
    }
    return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值