首页 > 其他分享 >YC303C [ 20240617 CQYC省选模拟赛 T3 ] Generals(generals)

YC303C [ 20240617 CQYC省选模拟赛 T3 ] Generals(generals)

时间:2024-06-19 16:24:50浏览次数:24  
标签:Generals YC303C 省选 int 一列 ans 方向 染满 dbinom

题意

给定一张 \(n \times m\) 的地图。

对于第 \(0\) 列,第 \(m + 1\) 列,第 \(0\) 行,第 \(n + 1\) 行,有 \(2n + 2m\) 个人,每个人面朝地图中心。

每个人走到别人染过色的位置,或走出地图,将走过的地方染色。

你需要求出共有多少种本质不同的染色方案。

\(n, m \le 10 ^ 6\)

Sol

直接做似乎很不好做,考虑一些特殊情况。

一个人都没有输出 \(1\)。

若只有两个方向,且两个方向对立,显然答案为 \(2\) 的次幂。

若只有两个方向的人且两个方向相邻,显然答案为 \(\dbinom{x + y}{x}\)。

考虑有三个方向的时候。

假设目前的三个方向分别为:向右,向下,向上,分别设人数为 \(x, y, z\)。

若当前有一列被贯通,那么右边部分变为两个方向且对立的情况。

考虑枚举第一列被贯通的位置。

那么显然对于左边的部分,一定有至少有一行被染满。

枚举当前最后一个染满的行 \(i\),则又变为两个子问题。

对于上方的是无限制,显然答案为 \(\dbinom{i + y - 1}{i - 1}\)。

对于下方不能被染满行,考虑这个东西的组合意义,那么很显然就是不能到达最后一列。

所以答案为 \(\dbinom{x - i + z}{x - i - 1}\)。

合起来:

\[\begin{aligned} & \sum_{i = 1} ^ {x} \dbinom{i + y - 1}{i - 1} \dbinom{x - i + z}{x - i - 1} \\ & = \sum_{i = 0} ^ {x - 1} \dbinom{i + y}{i} \dbinom{x - i + z - 1}{x - i - 1} \\ &= \dbinom{x + y + z - 1}{x - 1} \end{aligned} \]

这样就搞完了。

考虑四个方向的,不难发现必定有一列或一行贯穿,可以只考虑一列的情况,而一行可以翻转得到。

枚举最后一列被染满的,右边部分就是标准的三方向问题,直接组合数搞完了,左边部分可以染满一列,设 \(f_i\) 表示前 \(i\) 列的方案数。

若当前一列染满,直接就是 \(f_{i - 1}\),而没染满就是说明前面没有任何一列染满,也是三方向问题。

最后考虑一下上下是否都有 \(1\),若都有 \(1\),当前答案与 \(f_i\) 都要 \(\times 2\)。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#define int long long
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
string read_() {
    string ans;
    char c = getchar();
    while (c != '0' && c != '1')
        c = getchar();
    while (c == '0' || c == '1')
        ans += c, c = getchar();
    return ans;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 1e6 + 5, M = 4e6 + 5, mod = 998244353;

int pow_(int x, int k, int p) {
    int ans = 1;
    while (k) {
        if (k & 1) ans = ans * x % p;
        x = x * x % p;
        k >>= 1;
    }
    return ans;
}

array <int, M> fac, inv;

void init(int n) {
    fac[0] = 1;
    for (int i = 1; i <= n; i++)
        fac[i] = fac[i - 1] * i % mod;
    inv[n] = pow_(fac[n], mod - 2, mod);
    for (int i = n; i; i--)
        inv[i - 1] = inv[i] * i % mod;
}

int C(int n, int m) {
    if (n < m || n < 0 || m < 0) return 0;
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int Y(int x, int y, int z) {
    if (!x) return (!y && !z);
    return C(x + y + z - 1, x - 1);
}

void Mod(int &x) {
    if (x >= mod) x -= mod;
    if (x < 0) x += mod;
}

bool _edmer;
signed main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    init(4e6);
    /* while (1) { */
        /* int x = read(), y = read(), z = read(); */
        /* write(Y(x, y, z)), puts(""); */
    /* } */
    int n = read(), m = read();
    string sL =  " " + read_(), sR = " " + read_(), sU = " " + read_(), sD = " " + read_();
    int tp1 = 0, tp2 = 0, tp3 = 0, tp4 = 0;
    for (int i = 1; i <= n; i++) tp1 += sL[i] == '1';
    for (int i = 1; i <= n; i++) tp2 += sR[i] == '1';
    for (int i = 1; i <= m; i++) tp3 += sU[i] == '1';
    for (int i = 1; i <= m; i++) tp4 += sD[i] == '1';
    int len = (tp1 && 1) + (tp2 && 1) + (tp3 && 1) + (tp4 && 1);
    if (len <= 1) return puts("1"), 0;
    if (len == 2) {
        if ((tp1 + tp2) && (tp3 + tp4))
            return write(C(tp1 + tp2 + tp3 + tp4, tp1 + tp2)), puts(""), 0;
        int res = 1;
        for (int i = 1; i <= n; i++)
            if (sL[i] == '1' && sR[i] == '1')
                res = res * 2ll % mod;
        for (int i = 1; i <= m; i++)
            if (sU[i] == '1' && sD[i] == '1')
                res = res * 2ll % mod;
        return write(res), puts(""), 0;
    }
    auto solve = [&](string tL, string tU, string tD, int _tp2, int _tp3, int _tp4) -> int {
        int ans = 0, sum = 0;
        int l1 = 0, l2 = 0, l3 = 0; //Left Up Down
        for (int i = 1; i <= n; i++) l1 += tL[i] == '1';
        for (int i = 1; i <= m; i++) {
            if (tU[i] == '0' && tD[i] == '0') continue;
            int tp0 = (tU[i] == '1' && tD[i] == '1') ? 2 : 1;
            sum += Y(l1, l2, l3), Mod(sum);
            sum = sum * tp0 % mod;
            if (tU[i] == '1') l2++;
            if (tD[i] == '1') l3++;
            ans += sum * Y(_tp2, _tp3 - l2, _tp4 - l3) % mod, Mod(ans);
        }
        return ans;
    };
    /* cerr << solve() << "@@" << endl, exit(0); */
    int ans = 0;
    ans += solve(sL, sU, sD, tp2, tp3, tp4), Mod(ans);
    swap(n, m);
    ans += solve(sU, sR, sL, tp4, tp2, tp1), Mod(ans);
    write(ans), puts("");
    return 0;
}

标签:Generals,YC303C,省选,int,一列,ans,方向,染满,dbinom
From: https://www.cnblogs.com/cxqghzj/p/18256474

相关文章

  • YC302A [ 20240617 CQYC省选模拟赛 T1 ] 构造字符串(string)
    题意你需要构造一个长度为\(n\)的字符串。使得后缀数组为给定的序列\(a\),\(\text{manacher}\)的回文序列为\(b\)。Sol注意到后缀数组实际上是一系列\(\le\)的限制,而\(\text{manacher}\)是一堆相等以及两个不相等的限制。若直接建边很难搞。考虑将限制统一,后缀数组......
  • generals.io 新手攻略
    规则咕咕策略开局攒12~15个兵并一次性占一条地图,如果地图大,那么就一条线的占,否则缩成一团,目的是尽可能避免开局遇到他人。然后看是扩充领土,记住,这个时候不要动王座上的兵,在25轮后每个会刷一个兵,用他向四周扩散,点住一个然后向四周走。尽可能让自己的王位半径7格内的地方都是自......
  • 省选阶段算法学习笔记
    一、高级数据结构计划时间:5.20-5.22这个板块欠的帐不多,但是介于它板子太多了,估计复习起来比较麻烦,就三天。这个可能会提前完成。link二、进阶动态规划计划时间:5.23-5.25这个板块不但总结没写,还忘得有点厉害???所以花三天吧。三、字符串算法计划时间:5.26-5.27这个板块总结写......
  • P10217 [省选联考 2024] 季风
    [原题链接](https://www.luogu.com.cn/problem/P10217) 发现一定是若干个整段数组和一个前缀,可以枚举长度模$n$的余数,即位前缀。记当前位置为$i$,当前$x$数组前缀和为$sum1$,$y$数组为$sum2$,$x$数组总和为$sumx$,$y$数组总和为$sumy$。整段数组的个数为$m$,答案即......
  • P6619 [省选联考 2020 A/B 卷] 冰火战士
    卡常题,服了首先看到这个像断头一样的题面。其实就是让你求当前温度下,冰人的能量和火人的能量的最小值的两倍。然后搞出一个冰人的后缀和,火人的前缀和,交点的左右取个max搞出一个前缀数组和一个后缀数组,因为这个带修,是区间修改单点查询,所以我们要用树状数组。然后在树状数组上倍......
  • YC282B [ 20240430 CQYC省选模拟赛 T2 ] 温柔(gentle)
    题意有\(n\)个魔法少女,每个魔法少女的法力为\(a_i\),她们要打败\(n\)个法力为\(b_i\)的怪兽!你需要构造\({c_n}\),使得对于给定的\(m\)组限制,满足:\(c_x\geb_x\landc_y\geb_y\)或\(c_y\geb_x\landc_x\geb_y\)。你需要\(\sum_{i=1}^n|c_i-a_i|\),并......
  • YC284A [ 2024054 CQYC省选模拟赛 T1 ] 数数(count)
    题意现在有四种物品,分别有\(n1,n2,n3,n4\)个,有多少种排列物品的方案使得任意两个相邻物品的种类不同。\(0\len1,n2\le500,0\len3,n4\le5\times10^4\)Sol注意到\(n1\),\(n2\)特别小。设四个物品分别为\(C,D,A,B\)。考虑先插入\(C,D\),再考虑\(A,......
  • YC281A [ 20240429 CQYC省选模拟赛 T1 ] 玫瑰(rose)
    题意给定数列\(A,B,C\),每次操作,你可以花\(1\)的代价将\(A_i\)或\(B_i\)或\(C_i\)增加\(1\)。求使得三个数列每个元素排名相同的最小代价。\(n\le500\)Sol很厉害的题目。首先注意到这个最优方案只和前缀最大值有关,考虑设\(f_{i,j,k}\)表示当前状态枚举到了......
  • [省选联考 2021 A 卷] 矩阵游戏
    如果直接构造的话由于有a范围的限制,同时还要满足b的性质,非常恶心。考虑将两个性质分开考虑。首先如果我们确定了矩阵的第一行和第一列,那么我们就可以确定这个矩阵了。我们先构造出一个合法的矩阵,然后再对矩阵的第一行和第一列进行微调,是所有数都没满足范围。容易想到,比如要将\(a_......
  • YC278A [ 20240420 CQYC省选模拟赛 T1 ] 作画(paint)
    题意给定排列\(S\),最初\(S_i=i\)。每次进行以下操作,进行\(t\)次。选择下标\(i,j\),使得\(S_i=S_j\)。求进行\(t\)次后,\(S\)有至少\(k\)种数字的概率。\(n\le10,t\le10^{18}\)。Sol考虑概率转方案,变为有多少种方案使得最终状态有\(k\)种数字。不......