ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Educational Codeforces Round 114 (Rated for Div. 2) E. Coloring T11 D43

2021-09-23 13:36:29  阅读:240  来源: 互联网

标签:状态 Educational Rated int 值为 Codeforces 一行 重复 mp


Educational Codeforces Round 114 (Rated for Div. 2) E. Coloring T11 D43

[传送门]( Problem - E - Codeforces (Unofficial mirror site, accelerated for Chinese users) )

思路

(思路借鉴牛客群犇

观察到: 若第一行为 11000 或 1010110 这种有连续的两个 1 或 0 的串,那么下一行只能与上一行取反,状态是确定的;若为 101010 或 010101 这种01间隔的串,下一行的串可以与之相等或相反

先考虑第一种情况,下一行与上一行取相反,那么我们把所有行压缩到两行,看这两行的状态,对于某一列:

  1. 若这列有两个连续的1或0,则这种情况是无解的。
  2. 若这列没有确定的 1和0,则这列是自由的(即可以选择 010101或101010这样排列)
  3. 否则这列就是固定的

那么答案就是 \(2^{自由列个数}\)。

考虑第二种情况,101010,下一行有两种状态,相反的状态上面以求得,只考虑相同的状态,相同的状态相当于把行列颠倒,计算相反的状态。

最后两种结果的出来的答案加起来再减去重复的个数。

考虑重复的个数,对于二维矩阵,只有$\begin{matrix}
0&1\
1&0\
\end{matrix} 和 \begin{matrix}
1&0\
0&1\
\end{matrix} $这两种会出现重复情况,那么扩展后会发现,重复情况只会取 {0,1,2} 三种情况。

自己实现非常乱。

下面参考代码为 Heltion 的代码,代码太精致优美了,做详细注释 //代码太妙了,膜拜

参考代码

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
constexpr int maxn = 1000000 + 1;
constexpr LL mod = 998244353;
LL pw[maxn];
struct {
    int c[3];
    // c[0]表示不合法的数量
    // c[1]表示固定列的数量
    // c[2]表示自由列的数量
    int s[maxn][2];
    //s 表示把这一列的状态压缩到两行
    // 考虑 s[x]
    // 若s[x][0]和s[x][1] 都有值,说明压缩的列中有连续相同的数字,不合法
    // 其中有一个有值,是固定列
    // 都无值,是自由列
    void erase(int x, int y, int z) {
    	
        c[not s[x][0] + not s[x][1]] -= 1; 
        s[x][(y ^ z) & 1] -= 1; //状态数量 -1
        c[not s[x][0] + not s[x][1]] += 1; 
        //上面一种状态转移到下面一种状态
       
    }
    void insert(int x, int y, int z) {
    	
        c[not s[x][0] + not s[x][1]] -= 1;
        s[x][(y ^ z) & 1] += 1;
        c[not s[x][0] + not s[x][1]] += 1;
        //同上
    }
    LL ans() {
        return c[0] ? 0 : pw[c[2]];
    }
    void init(int n) {
        c[2] = n;
    }
}R, C;
int main() {
    cin.tie(nullptr)->sync_with_stdio(false);
    //map保存每个点的状态
    map<pair<int, int>, int> mp;
    //计算 2的次方
    for (int i = 0; i < maxn; i += 1) pw[i] = i ? pw[i - 1] * 2 % mod : 1;
    int n, m, k;
    cin >> n >> m >> k;
    R.init(n); //初始化自由列/行的个数
    C.init(m);
    int c[2] = {}; //记录重复的值
    // c[0]表示1010这种情况出现过没有
    // c[1]表示0101这种情况出现过没有
    for (int i = 0; i < k; i += 1) {
        int x, y, z;
        cin >> x >> y >> z;
        if (mp.count({x, y})) {//若之前被赋值了,先删去
            
            c[(x ^ y ^ mp[{x, y}]) & 1] -= 1;
            R.erase(x, y, mp[{x, y}]);
            C.erase(y, x, mp[{x, y}]);
            mp.erase({x, y});
        }
        if (z != -1) {
            //关于 (x ^ y ^ z) & 1  考虑一行
            //若是 101010  则值为 1 1 1 1 1 1 对应为c[1]=5,c[0]=0;
            //表示有一种情况出现了,重复值为 1 下面同理
            //若是 010101  则值为 0 0 0 0 0 0 重复值为 1
            //若是 110010  则值为 1 0 0 1 1 1 重复值为 0
            c[(x ^ y ^ z) & 1] += 1;
            R.insert(x, y, z);
            C.insert(y, x, z);
            mp[{x, y}] = z;
        }
        //c[1]和c[2]都等于0 ,说明矩阵中没有已填充数字,重复值为2
        //有一个>0,另一个等于0 ,重复值为1
        //两个都>0,说明矩阵中有连续相同的数字,重复值为0
        cout << (R.ans() + C.ans() + mod - not c[0] - not c[1]) % mod << "\n";
    }
    return 0;
}

标签:状态,Educational,Rated,int,值为,Codeforces,一行,重复,mp
来源: https://www.cnblogs.com/Suki-Sugar/p/15323760.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有