• 题解 CF1503E 2-Coloring [*easy]


    感觉这题是一道细节比较多但是不难的题,配不上这个 *3100 的标签,连萌新都能独立做出来......

    题面

    给定一个 (n imes m) 的矩阵,要你把矩阵的每一个格子染成蓝的或黄的,要求每一行的蓝色格子段数(连通块数)恰好有一个,每一列的黄格子段数恰好有一个。求染色方案数,答案对 (998244353) 取模。

    数据范围:(1 le n, m le 2000)

    题解

    这里的 (n, m) 可能是反的,但是不影响答案(

    观察蓝色的线段。

    经过手膜大致可以发现可以分成两类情况讨论

    第一类

    蓝色的分成两个部分,上面一个下面一个。

    这两个部分都是 "单峰" 的。

    要求两个部分的 "高度" 之和恰好为 (m)

    考虑美剧第一个的高度和两个峰值的位置(枚举最左边的或最右边的即可)

    [2 sumlimits_{z = 1}^{m - 1} sumlimits_{i = 1}^{n - 1} sumlimits_{j = i + 1}^{n} inom{i + z - 1}{z} inom{n - i + z - 1}{z - 1} inom{j + m - z - 2}{m - z - 1} inom{n - j + m - z}{m - z} ]

    第二类

    蓝色的分成两个部分,上面一个下面一个。

    要求两个部分的 "高度" 之和 (> m)

    枚举高度,然后枚举这个交的部分(黑线)的 (x) 坐标即可。

    [2 sumlimits_{p = 1}^{n} sumlimits_{i = 1}^{m - 1} sumlimits_{j = m - i + 1}^{m - 1} inom{p + i - 1}{i} inom{n - p + m - j - 1}{m - j - 1} inom{p + m - i - 1}{m - i - 1} inom{n - p + j - 1}{j} ]

    现在的复杂度是 (Theta(n^3)) 的((n, m) 同阶)

    但是这两个柿子是可以前缀和优化的,做到 (Theta(n^2))


    上面这些柿子是哪里来的?

    考虑一个长为 (x) 的不严格单调下降序列,要求第一个值 (le y)

    这个是经典的插板法,先化成严格的,然后再插板,一个板代表这个序列的一个元素。那么答案就是 (inom{x+y}{x})

    那里要乘以 (2) 是因为我们钦定了上面和下面的左右关系。

    你有没有感觉这两个柿子是一模一样的?

    嗯是的,其实这两种情况只是 (n. m) 交换了一下,本质是差不多的(

    代码

    #include<bits/stdc++.h>
    #define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
    #define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
    #define ll long long
    #define pii pair<int, int>
    #define db double
    #define x first
    #define y second
    #define ull unsigned long long
    #define sz(a) ((int) (a).size())
    #define vi vector<int>
    using namespace std;
    const int N = 4e5 + 7, mod = 998244353;
    int ns, n, m;
    int fac[N], inv[N], ifac[N];
    void init(int x) {
    	fac[0] = ifac[0] = inv[1] = 1;
    	L(i, 2, x) inv[i] = (ll) inv[mod % i] * (mod - mod / i) % mod;
    	L(i, 1, x) fac[i] = (ll) fac[i - 1] * i % mod, ifac[i] = (ll) ifac[i - 1] * inv[i] % mod;
    }
    int C(int x, int y) {
    	return x < y || y < 0 ? 0 : (ll) fac[x] * ifac[y] % mod * ifac[x - y] % mod;
    }
    int main() {
    	cin >> n >> m, init(max(n, m) * 4);
    	L(z, 1, m - 1) {
    		int now = 0;
    		R(r1, n - 1, 1) {
    			(now += (ll) C(r1 + m - z - 1, m - z - 1) * C(n - r1 + m - z - 1, m - z) % mod) %= mod;
    			(ns += (ll) C(r1 + z - 1, z) * C(n - r1 + z - 1, z - 1) % mod * now % mod) %= mod;
    		}
    	}
    	L(p, 1, n) {
    		int now = 0;
    		L(z1, 1, m - 1) {
    			(now += (ll) C(n - p + z1 - 2, z1 - 2) * C(n - p + m - z1, m - z1 + 1) % mod) %= mod; 
    			(ns += (ll) C(p + z1 - 1, z1) * C(p + m - z1 - 1, m - z1 - 1) % mod * now % mod) %= mod;	
    		}
    	}
    	ns = (ll) ns * 2 % mod;
    	cout << ns << "
    ";
    	return 0;
    } 
    

    祝大家学习愉快!

  • 相关阅读:
    变量声明和定义的关系
    STL之Vector
    STL之顺序容器
    类成员函数可以为回调函数吗
    排序
    名字查找
    Java 写 Log
    Spring 框架中注释驱动的事件监听器详解
    Centos7 安装gitLab
    世界经济史是一部基于假象和谎言的连续剧
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/14616877.html
Copyright © 2020-2023  润新知