Luogu 3631 [APIO 2011] 方格染色

2023-05-16

          • 传送门
          • 思路
          • 参考代码
          • 细节

传送门
思路

  很不错的一道题,用到的东西不深,但是要想到确实需要一定思维。

  一开始我想的是动态规划,发现如果要设状态需要知道一个格子左边,上边和左上边三个格子的状态。然后发现转移时还要枚举右上角是什么,有点麻烦,但是应该可做。

  思考题目时,如果题目不是一眼题,即使没有部分分,也应该从两个方面去想:
1. 数据规模较小的情况(如果题目的正解是多项式算法,那么最好往多项式算法去想,这时就不要纠结于指数级算法了)
2. 特殊情况,比如较少限制条件的情况

  但是我忘记了考虑特殊情况,于是就凉了。


  考虑一下,如果没有人来涂色,答案将会是多少。考虑逐层构造,发现,当构造完第一行时(第一行本身没有限制),第二行只需要知道第一个列是什么,就能唯一确定第二行。推广一下,便能发现:只要确定了第一行和第一列,那么就能得到唯一的构造方法这跟普及组的熄灯问题是类似的

  现在我们把涂了的颜色加进来,看看会有哪些影响。影响无非就是原来的某个方案不符合已经涂色的内容。如果我们能够通过已经涂色的倒推出还没有涂色的,那么问题也差不多解决了

  下面就需要一些思维高度了。我们将题意转换一下,将颜色抽象为 0 0 1,则一个 2×2 2 × 2 的方阵里要么出现了 3 3 0,要么出现了 3 3 1这等价于是说这个 2×2 2 × 2 的方阵异或和为 1 1

  对于 (x,y)(x,y>1),我们将左上角为 (1,1)(x1,y1) ( 1 , 1 ) ∼ ( x − 1 , y − 1 ) 的所有 2×2 2 × 2 的方阵中的四个元素都选择一遍(要重复选择,因为异或的性质,选偶数次等价于没有选),那么这些元素的异或和显然与 (x1)×(y1) ( x − 1 ) × ( y − 1 ) 有关(因为每个方阵的四个数的异或和为 1 1 ,共有 (x1)×(y1) 个方阵)。若上式为奇数,则异或和为 1 1 ,否则为 0。又因为异或的性质,可以发现,这么选等价于只选择了 (1,1),(x,1),(1,y),(x,y) ( 1 , 1 ) , ( x , 1 ) , ( 1 , y ) , ( x , y ) 这四个方格。换句话说,我们知道了这四个数的异或和!

  我们枚举 (1,1) ( 1 , 1 ) 0 0 还是 1,就能得到两个数的异或和,这可以用带关系的并查集或者带反集合的并查集解决。如果出现了非法的情况,说明无解。最终的答案取决于两种颜色都能选的集合的个数。细节留给你们,我将会在参考代码后给出。

参考代码

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <cctype>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <functional>
typedef long long LL;
typedef unsigned long long ULL;
using std::cin;
using std::cout;
using std::endl;
typedef int INT_PUT;
INT_PUT readIn()
{
    INT_PUT a = 0; bool positive = true;
    char ch = getchar();
    while (!(ch == '-' || std::isdigit(ch))) ch = getchar();
    if (ch == '-') { positive = false; ch = getchar(); }
    while (std::isdigit(ch)) { a = a * 10 - (ch - '0'); ch = getchar(); }
    return positive ? -a : a;
}
void printOut(INT_PUT x)
{
    char buffer[20]; int length = 0;
    if (x < 0) putchar('-'); else x = -x;
    do buffer[length++] = -(x % 10) + '0'; while (x /= 10);
    do putchar(buffer[--length]); while (length);
}

const int mod = int(1e9);
const int maxn = int(1e6) + 5;
int n, m, k;
int x[maxn];
int y[maxn];
int c[maxn];

struct DS
{
    int parent[maxn * 4];
    int color[maxn * 4];
    void clear(int size)
    {
        for (int i = 1; i <= size; i++)
            parent[i] = i;
        for (int i = 1; i <= size; i++)
            color[i] = -1;
    }
    int find(int x)
    {
        return x == parent[x] ? x : (x = find(parent[x]));
    }
    bool unite(int x, int y)
    {
        if (~color[find(x)] && ~color[find(y)] && color[find(x)] != color[find(y)])
            return false;
        color[find(x)] = std::max(color[find(x)], color[find(y)]);
        parent[find(y)] = find(x);
        return true;
    }
    bool judge(int x, int y)
    {
        return find(x) == find(y);
    }
} ds;

LL power(LL x, int y)
{
    LL ret = 1;
    while (y)
    {
        if (y & 1) ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}

void run()
{
    n = readIn();
    m = readIn();
    k = readIn();
    bool bset[2] = {};
    for (int i = 1; i <= k; i++)
    {
        x[i] = readIn();
        y[i] = readIn();
        c[i] = readIn();
        if (x[i] == 1 && y[i] == 1)
            bset[c[i]] = true;
    }
    for (int i = 1; i <= k; i++)
    {
        x[i]--;
        y[i]--;
    }

    int ans = 0;
    int delta = n + m - 2;
#define THIS(x) (x)
#define ANTI(x) ((x) + delta)
    if (!bset[0])
    {
        bool bOk = true;
        ds.clear(delta << 1);
        for (int i = 1; i <= k; i++)
        {
            if (!x[i] && !y[i])
                continue;
            else if (!x[i])
            {
                if (~ds.color[ds.find(THIS(y[i]))] &&
                    ds.find(THIS(y[i])) != c[i])
                {
                    bOk = false;
                    break;
                }
                ds.color[ds.find(THIS(y[i]))] = c[i];
                ds.color[ds.find(ANTI(y[i]))] = !c[i];
            }
            else if (!y[i])
            {
                if (~ds.color[ds.find(THIS(m - 1 + x[i]))] &&
                    ds.find(THIS(m - 1 + x[i])) != c[i])
                {
                    bOk = false;
                    break;
                }
                ds.color[ds.find(THIS(m - 1 + x[i]))] = c[i];
                ds.color[ds.find(ANTI(m - 1 + x[i]))] = !c[i];
            }
            else
            {
                if ((x[i] & 1) && (y[i] & 1))
                {
                    if (!ds.unite(THIS(m - 1 + x[i]), ANTI(y[i])) ||
                        !ds.unite(ANTI(m - 1 + x[i]), THIS(y[i])) ||
                        ds.judge(THIS(m - 1 + x[i]), ANTI(m - 1 + x[i])) ||
                        ds.judge(THIS(y[i]), ANTI(y[i])))
                    {
                        bOk = false;
                        break;
                    }
                }
                else
                {
                    if (!ds.unite(THIS(m - 1 + x[i]), THIS(y[i])) ||
                        !ds.unite(ANTI(m - 1 + x[i]), ANTI(y[i])) ||
                        ds.judge(THIS(m - 1 + x[i]), ANTI(m - 1 + x[i])) ||
                        ds.judge(THIS(y[i]), ANTI(y[i])))
                    {
                        bOk = false;
                        break;
                    }
                }
            }
        }
        if (bOk)
        {
            int ex = 0;
            for (int i = 1; i <= (delta << 1); i++)
            {
                if (ds.parent[i] != i) continue;
                if (!~ds.color[i])
                    ex++;
            }
            ex >>= 1;
            ans = (ans + power(2, ex)) % mod;
        }
    }
    if (!bset[1]) // copy and modify a !
    {
        bool bOk = true;
        ds.clear(delta << 1);
        for (int i = 1; i <= k; i++)
        {
            if (!x[i] && !y[i])
                continue;
            else if (!x[i])
            {
                if (~ds.color[ds.find(THIS(y[i]))] &&
                    ds.find(THIS(y[i])) != c[i])
                {
                    bOk = false;
                    break;
                }
                ds.color[ds.find(THIS(y[i]))] = c[i];
                ds.color[ds.find(ANTI(y[i]))] = !c[i];
            }
            else if (!y[i])
            {
                if (~ds.color[ds.find(THIS(m - 1 + x[i]))] &&
                    ds.find(THIS(m - 1 + x[i])) != c[i])
                {
                    bOk = false;
                    break;
                }
                ds.color[ds.find(THIS(m - 1 + x[i]))] = c[i];
                ds.color[ds.find(ANTI(m - 1 + x[i]))] = !c[i];
            }
            else
            {
                if (!((x[i] & 1) && (y[i] & 1)))
                {
                    if (!ds.unite(THIS(m - 1 + x[i]), ANTI(y[i])) ||
                        !ds.unite(ANTI(m - 1 + x[i]), THIS(y[i])) ||
                        ds.judge(THIS(m - 1 + x[i]), ANTI(m - 1 + x[i])) ||
                        ds.judge(THIS(y[i]), ANTI(y[i])))
                    {
                        bOk = false;
                        break;
                    }
                }
                else
                {
                    if (!ds.unite(THIS(m - 1 + x[i]), THIS(y[i])) ||
                        !ds.unite(ANTI(m - 1 + x[i]), ANTI(y[i])) ||
                        ds.judge(THIS(m - 1 + x[i]), ANTI(m - 1 + x[i])) ||
                        ds.judge(THIS(y[i]), ANTI(y[i])))
                    {
                        bOk = false;
                        break;
                    }
                }
            }
        }
        if (bOk)
        {
            int ex = 0;
            for (int i = 1; i <= (delta << 1); i++)
            {
                if (ds.parent[i] != i) continue;
                if (!~ds.color[i])
                    ex++;
            }
            ex >>= 1;
            ans = (ans + power(2, ex)) % mod;
        }
    }
    printOut(ans);
}

int main()
{
    run();
    return 0;
}
细节

  (这取决于具体实现)首先看有没有对 (1,1) ( 1 , 1 ) 染色,如果有,则只有一种情况,否则 (1,1) ( 1 , 1 ) 的颜色有两种情况。

  对于所有对第一行或者对第一列(除了 (1,1) ( 1 , 1 ) )的染色,我们将所在被染位置所在集合进行标记,标记为染成了什么颜色,相应的它的反集合也要进行标记。如果它已经被标记了并且颜色不同,说明方案不合法。

  进行并查集的合并操作时,我们同样先检查这两个集合是否已经被染色。若已经被染色了,且染的颜色不同,说明不合法,否则将新的集合也染上相应颜色。

  最后,我们看并查集中有多少个集合没有被打上染色标记。设该值为 x x ,显然,由于反集合与原集合有对称性,忽视反集合后应该有 x2 个集合没有被打上染色标记。那么在这种情况下的答案为 2x 2 x 。最终答案为(至多)两种情况的答案之和。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Luogu 3631 [APIO 2011] 方格染色 的相关文章

  • 2011

    2011 Problem Description The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits G
  • ITIL 2011 -- 服务运营的5个流程简介 (上)

    要做一个IT运维管理的项目 xff0c 客户提到了ITIL xff08 IT Infrastructure Library xff09 xff0c 所以谈需求之前我研究了一下ITIL xff0c 发现东西比较多 xff0c 但是里面的服务运
  • luogu P2078 朋友

    题目背景 小明在A公司工作 xff0c 小红在B公司工作 题目描述 这两个公司的员工有一个特点 xff1a 一个公司的员工都是同性 A公司有N名员工 xff0c 其中有P对朋友关系 B公司有M名员工 xff0c 其中有Q对朋友关系 朋友的朋
  • luogu p2651 添加括号Ⅲ

    题目描述 现在给出一个表达式 xff0c 形如a1 a2 a3 an 如果直接计算 xff0c 就是一个个除过去 xff0c 比如1 2 1 4 61 1 8 然而小A看到一个分数感觉很不舒服 xff0c 希望通过添加一些括号使其变成一个整
  • Luogu 3634 [APIO 2012] 守卫

    传送门思路正解参考代码 传送门 思路 感觉自己越来越笨了 首先 xff0c 很明显这道题需要把没有看到忍者的区间给删去 xff0c 可以用前缀和 O n O n 处理 xff0c 然后对没有删去的地方重新标号 重新标号时 xff0c 需要对
  • Luogu 3645 [APIO 2015] 雅加达的摩天楼

    传送门思路正解参考代码Update 传送门 思路 唉 xff0c 我太弱了 xff0c 我都看出来要分块了 xff0c 就是做不来 不过终于把题读对了 先来看子任务三怎么做 显然可以有一个 O m 2 O m 2
  • UOJ 2016 [APIO 2016] Gap

    传送门思路参考代码交互题 交互题大致形式Windows 平台下 xff08 Dev C 43 43 xff09 Ubuntu 平台下 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 题也做不来 这道题简直就是利用
  • Luogu 3778 [APIO 2017] 商旅

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 看到这道题就想到了二分答案找负环 xff0c 但是怎么做呢 xff1f 完全不会 唉 xff0c 我太弱啦 xff01 先注意题目中说可以重复经过点和边 x
  • Luogu 1117 [NOI 2016] 优秀的拆分

    传送门思路利用后缀数组解决重复子串问题注意事项参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 连暴力都想不到 xff0c 唉 xff0c 我太弱啦 xff01 考虑暴力法 xff0c 可以枚举一个中间点
  • Luogu 3822 [NOI 2017] 整数

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 当年网同这道题还拿了 16 16 分 xff0c 现在一分都不会做了 xff0c 唉 xff0c 我太弱啦 xff01 这道题其实是很不错的 x
  • APIO 2018 Practice Session T1 Wedding cake

    没有传送门题目大意思路参考代码熟悉环境 没有传送门 题目大意 给你一个长度为 n n 的正整数序列 a i ai xff0c 要求构造出 n n 个小数 使得它们的和为 1 1 xff0c 且每个数小数点后恰好有
  • APIO 2018 Practice Session T3 / CF 936C Lock Puzzle

    传送门题目大意思路参考代码总结 传送门 题目大意 给你一个字符串 origin xff0c 一个字符串 target xff0c 长度均为 n n 要求在 3 n 3n xff08 5 2 n 5 2
  • Luogu 2114 [NOI 2014] 起床困难综合症

    传送门思路参考代码 传送门 思路 按位贪心 但是我太弱了 xff0c 明明可以 O n O n 预处理 xff0c 我却只会 O 32 n O
  • Luogu 2414 [NOI 2011] 阿狸的打字机

    文章目录 传送门思路参考代码总结 传送门 思路 首先我们甚至不能单独保存每个字符串 xff0c 因为总长度可以达到 O n 2
  • 2011/11/26

    听雨听风听愁绵 xff0c 疏雨薄衣心无涟
  • CentOS8.3.2011无法联网解决方案

    1 切换到ifcfg ensXX目录下 cd etc sysconfig network scripts 2 编辑ifcfg ensXX文件 vim ifcfg ens33 3 修改 BOOTPROTO 61 dhcp 并且修改 ONBOO
  • 我的2011--衣带渐宽终不悔,为伊消得人憔悴

    古今之成大事业 大学问者 xff0c 必经过三种之境界 xff1a 34 昨夜西风凋碧树 独上高楼 xff0c 望尽天涯路 34 此第一境也 34 衣带渐宽终不悔 xff0c 为伊消得人憔悴 34 此第二境也 34 众里寻他千百度 xff0
  • 2011,我和CSDN亲密接触的一年

    从CSDN刚刚发出这次征文活动的时候 xff0c 就有一种想参加的冲动 xff0c 总想说些什么 xff0c 迟迟直到今天才开始下笔 和大家一样 xff0c 我也是一名普通的计算机研发人员 xff0c 说挨踢者也行 xff0c 说码农亦可
  • ---------------------------谨以此文献给我的2011-----------------------------------

    2011年就快过去了 xff0c 回首我的2011 xff0c 有收获 xff0c 也有失落 xff0c 有胜利 xff0c 也有失败 有高兴的事情 xff0c 也有很多不高兴的事情 如果说往事不堪回首来总结的话 xff0c 未免有点太过于
  • 写在2011

    很早就想写点东西了 xff0c 可晃荡晃荡地就到了2011年最后一刻 我想是要写点东西了 2011年 xff0c 我有太多的感触 这一年是我第一次在异地迎接农历新年了 xff0c 对 xff0c 当时的感觉很刺激 xff0c 刺激得让我和当

随机推荐

  • GetExitCodeProcess 所需运行时间

    GetExitCodeProcess 在 Windows 中用于获取进程的返回代码 这个看上去只有一个读操作的函数运行速度如何呢 xff1f 直觉上不会很快 xff0c 因为它肯定涉及操作系统进程表的操作 下面做了一个实验 代码 xff1a
  • C++ 继承时返回值或参数的类型是父类的行为

    见以下代码的 base t amp operator 61 const base t amp another 还没有搞清楚 span class token macro property span class token directive
  • LaTeX 007:texify 调用 zhmakeindex

    如文档所述 xff0c 在系统增加一个值为 zhmakeindex 路径的环境变量 MAKEINDEX 即可
  • 转载:LaTeX 定义参数变长的命令

    本文作者 xff1a Liam Huang 本文链接 xff1a https liam page 2017 07 30 define a new command with different amount of parameters in
  • 一个简单的 Lex 词法分析程序示例

    作为一个学习 Lex 词法分析程序的例子 xff0c 下面的 lex 程序将会生成一个分析 LaTeX 中命令的词法分析器 下面的程序包含了很多 lex 语言的语法 xff0c 正则表达式除外 正则表达式的用法网上比较多 xff0c 这里不
  • mysql数据库conf配置详解

    mysqld port 61 6033 skip grant tables datadir 61 usr tools mysql data socket 61 usr tools mysql mysql sock user 61 mysql
  • LaTeX 008:比较方便的键入下划线的方式

    在 LaTeX 中 xff0c 我们有时会需要输入下划线 直接键入 是不行的 xff0c 会出现的编译错误 xff0c 正如网友所述 xff0c LaTeX 为了简化对编译错误的处理禁止在文本模式 xff08 text mode xff09
  • LaTeX 009:自定义带有 * 号的命令

    LaTeX 中 xff0c 我们经常见到 section 和 section xff0c 分别表示有编号的 section 和没有编号的 section 我们也想自己定义带有 号的命令 xff0c 但写下面的代码时却报错了 xff1a ne
  • 2022 New Year‘s Resolution

    Some Might Say 2022 New Year 39 s Resolution Some might say we are on the edge of the new era Always are they saying thi
  • C++ 多线程编程导论(中)

    受篇幅限制 xff0c 上半部分不再更新 xff0c 填坑的新内容都放在此文章中 文章目录 参考资料线程安全 xff08 续 xff09 互斥访问 互斥体 xff08 mutex xff09 和锁 xff08 lock xff09 什么是互
  • C++ 使用模板序列化/反序列化固定键值对

    仅是一个原型 xff0c 留作记录 我感觉可以写出非常逆天的代码 span class token macro property span class token directive hash span span class token d
  • 编译原理习题两则(龙书,写出语言的正则定义)

    3 3 5 3 注释 xff0c 即 和 之间的串 xff0c 且串中没有不在双引号 xff08 34 xff09 中的 注 xff1a 假设双引号是匹配的 思路 xff1a 从空串开始写 xff0c 写出整体框架后 xff0c 通过分类讨
  • 2023 New Year‘s Resolution

    This Is Game 2023 New Year 39 s Resolution My 2022 ended with a day of game I am convinced that I am not to blame becaus
  • 补录:2018 和 2019 New Year‘s Resolution

    前言 xff1a 吉光片羽 xff0c 以飨读者 2018 New Year 39 s Resolution One year and a half ago I felt that life in 2020 would be quite d
  • 原博文地址

    由于账号问题 xff0c 现更改为这个账号 xff0c 以下为原博文地址 使用WH MOUSE LL钩子来判断按键是否是mouse event模拟的 http blog csdn net qq 26140973 article detail
  • [NOI 2003] 文本编辑器 Splay 维护序列 / 块状链表

    传送门 xff08 JZOJ xff09 xff08 第一道全国决赛题 xff09 解法 1 xff1a 使用 Splay 维护 不管怎么说 xff0c 总和刚刚学过的迎合上了 这道题可以直接上 Splay 维护线性序列 xff0c 光标位
  • 一次macOS的升级填坑(macOS Catalina - macOS Monterey)

    目录 小序一 升级前操作二 升级中三 问题填坑1 像我一样长时间卡在一个进度条怎么办2 在更新途中重启过电脑 xff08 完整流程填坑 xff09 3 安装之后不能开机 xff0c 如何紧急拷贝资料4 安装不成功 xff0c 如何重新安装系
  • CF 713C Sonya and Problem Wihtout a Legend

    文章目录 传送门题目大意正解通过维护关键点来维护信息参考代码 传送门 题目大意 给定一个长度为 n n 3000
  • Luogu 3642 [APIO 2016] 烟火表演

    传送门引例 xff08 上一道题 xff09 凸函数一开始的思路正解参考代码总结 传送门 引例 xff08 上一道题 xff09 凸函数 回忆我们上一道题是怎么做的 我们维护的东西的实质是一个 xff08 下 xff09 凸函数 由于我们的
  • Luogu 3631 [APIO 2011] 方格染色

    传送门思路参考代码细节 传送门 思路 很不错的一道题 xff0c 用到的东西不深 xff0c 但是要想到确实需要一定思维 一开始我想的是动态规划 xff0c 发现如果要设状态需要知道一个格子左边 xff0c 上边和左上边三个格子的状态 然后