[日常训练]三视图(组合计数+容斥)

Description

给定两个长度为 \(n\) 的数组 \(a,b\)。

要求给一个 \(n×n\) 的矩阵的每个位置填上一个非负整数,使得第 \(i\) 行的最大值为 \(a_i\),第 \(j\) 列的最大值为 \(b_j\)。

求方案数对 \(998244353\) 取模的结果。

\(1\leq n\leq 10^5\),\(1\leq a,b\leq 10^9\)。

Solution

显然可以把 \(a,b\) 分别降序排序,不影响结果。

记 \(c_{i,j}=min(a_i,b_j)\)。考虑将 \(c_{i,j}\) 相同的位置放在一起处理。

显然 \(c_{i,j}\) 相同的位置会形成一个 \(\lceil\) 反 \(L\) 形 \(\rfloor\)。

具体地,将 \(a,b\) 降序排序后,若 \(a_{x_1}\) ~ \(a_{x_2}\) 和 \(b_{y_1}\) ~ \(b_{y_2}\) 都是 \(s\),则所有满足以下条件的 \(i,j\) 都有 \(c_{i,j}=s\):

  1. \(1\leq i\leq x_2\) 且 \(1\leq j\leq y_2\)
  2. \(x_1\leq i\) 或 \(y_1\leq j\)。

那么现在这个 \(\lceil\) 反 \(L\) 形 \(\rfloor\) 的填数要满足以下条件:

  1. 每个格子的数都在 \([0,s]\) 中。
  2. 第 \(x_1\) ~ \(x_2\) 行的最大值是 \(s\)。
  3. 第 \(y_1\) ~ \(y_2\) 列的最大值是 \(s\)。

考虑容斥,设 \(f(i)\) 表示第 \(x_1\) ~ \(x_2\) 行中,至少有 \(i\) 行的最大值不是 \(s\) 的方案(需要保证第 \(y_1\) ~ \(y_2\) 列的最大值是 \(s\))。

令 \(l_x=x_2-x_1+1,l_y=y_2-y_1+1\)。(即行数和列数)

那么 \(ans=\sum_{i=0}^{lx}(-1)^if(i)\)。

考虑怎么算 \(f(i)\):

先填强制最大值不是 \(s\) 的那 \(i\) 行:首先从 \(l_x\) 行中选出 \(i\) 行,然后这 \(i\) 行最大值不是 \(s\),所以这 \(i\) 行的所有格子都只能填 \([0,s-1]\)。

这一部分的方案数:\(c(l_x,i)×s^{i×y_2}\)。

接着考虑 \(\lceil\) 保证第 \(y_1\) ~ \(y_2\) 列的最大值是 \(s\) \(\rfloor\):第 \(y_1\) ~ \(y_2\) 列中,每列已经填了 \(i\) 个,还剩 \(x_2-i\) 个没填。显然每列的这 \(x_2-i\) 个格子中,必定至少有一个 \(s\)。

这一部分的方案数:\(((s+1)^{x_2-i}-s^{x_2-i})^{l_y}\)。

还剩下 \((l_x-i)(y_1-1)\) 个格子,随便填。

这一部分的方案数:\((s+1)^{(l_x-i)(y_1-1)}\)。

所以:
\[f(i)=c(l_x,i)×s^{i×y_2}×((s+1)^{x_2-i}-s^{x_2-i})^{l_y}×(s+1)^{(l_x-i)(y_1-1)}\]

时间复杂度 \(O(n (\log n+\log 1e9))\)。

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

template <class t>
inline void read(t & res)
{
    char ch;
    while (ch = getchar(), !isdigit(ch));
    res = ch ^ 48;
    while (ch = getchar(), isdigit(ch))
    res = res * 10 + (ch ^ 48);
}

const int e = 2e5 + 5, mod = 1e9 + 7;
int n, a[e], b[e], d[e], m, ans = 1, fac[e], inv[e];

inline int ksm(int x, int y)
{
    int res = 1;
    while (y)
    {
        if (y & 1) res = (ll)res * x % mod;
        y >>= 1;
        x = (ll)x * x % mod;
    }
    return res;
}

inline int c(int x, int y)
{
    if (x < y) return 0;
    return (ll)fac[x] * inv[y] % mod * inv[x - y] % mod;
}

inline int plu(int x, int y)
{
    (x += y) >= mod && (x -= mod);
    return x;
}

inline int sub(int x, int y)
{
    (x -= y) < 0 && (x += mod);
    return x;
}

inline int solve(int la, int lb, int ra, int rb, int s)
{
    int res = 0, i, a = ra - la, b = rb - lb;
    for (i = 0; i <= a; i++)
    {
        int tmp = (ll)c(a, i) * ksm(s, (ll)i * rb % (mod - 1)) % mod *
        ksm(sub(ksm(s + 1, ra - i), ksm(s, ra - i)), b) % mod *
        ksm(s + 1, (ll)(a - i) * lb % (mod - 1)) % mod;
        if (i & 1) res = sub(res, tmp);
        else res = plu(res, tmp);
    }
    return res;
}

int main()
{
    read(n);
    int i;
    for (i = 1; i <= n; i++) read(a[i]), d[++m] = a[i];
    for (i = 1; i <= n; i++) read(b[i]), d[++m] = b[i];
    sort(d + 1, d + m + 1);
    m = unique(d + 1, d + m + 1) - d - 1;
    reverse(d + 1, d + m + 1);
    sort(a + 1, a + n + 1); reverse(a + 1, a + n + 1);
    sort(b + 1, b + n + 1); reverse(b + 1, b + n + 1);
    fac[0] = 1;
    for (i = 1; i <= n; i++) fac[i] = (ll)fac[i - 1] * i % mod;
    inv[n] = ksm(fac[n], mod - 2);
    for (i = n - 1; i >= 0; i--) inv[i] = (ll)inv[i + 1] * (i + 1) % mod;
    int la = 0, lb = 0;
    for (i = 1; i <= m; i++)
    {
        int ra = la, rb = lb;
        while (ra < n && a[ra + 1] == d[i]) ra++;
        while (rb < n && b[rb + 1] == d[i]) rb++;
        ans = (ll)ans * solve(la, lb, ra, rb, d[i]) % mod;
        la = ra; lb = rb;
    }
    cout << ans << endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/cyf32768/p/12196043.html

时间: 2024-10-26 19:00:12

[日常训练]三视图(组合计数+容斥)的相关文章

SPOJ - AMR11H Array Diversity (水题排列组合或容斥)

题意:给定一个序列,让你求两种数,一个是求一个子序列,包含最大值和最小值,再就是求一个子集包含最大值和最小值. 析:求子序列,从前往记录一下最大值和最小值的位置,然后从前往后扫一遍,每个位置求一下数目就好. 求子集可以用排列组合解决,很简单,假设最大值个数是 n,最小值的数是 m,总数是 N,答案就是 (2^n-1) * (2^m-1)*2^(N-m-n), 当然要特殊判断最大值和最小值相等的时候. 当然也可以用容斥来求,就是总数 - 不是最大值的数目 - 不是最小值的数目 + 不是最大值也不是

hdu5072 Coprime 2014鞍山现场赛C题 计数+容斥

http://acm.hdu.edu.cn/showproblem.php?pid=5072 Coprime Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 354    Accepted Submission(s): 154 Problem Description There are n people standing in a

BZOJ 3456 NTT图的计数 容斥

思路: RT 懒得写了 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N=(1<<18)+5,mod=1004535809; int tmp[N],R[N],fac[N],A[N],B[N],C[N],niB[N]; int pow(ll x,ll y){

「JSOI2019」神经网络(容斥+组合计数+背包dp)

Address luogu5333 loj3102 Solution 容易发现,一条哈密顿回路本质上就是:把每棵树都拆成若干条有向路径,再把所有的有向路径连接成环,环上的相邻两条有向路径不可以来自同一棵树. 先求出 \(g_{i,j}\) 表示把第 \(i\) 棵树拆成 \(j\) 条有向路径的方案数. 考虑 \(\text{dp}\),记 \(f_{u,i,0/1/2/3}\) 分别表示:\(u\) 的子树拆成 \(i\) 条路径,\(u\) 是路径起点,是路径终点,单点成路径,既不是路径起点

HDU 4135 Co-prime(组合+容斥)

Problem Description Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N. Two integers are said to be co-prime or relatively prime if they have no common positive divisors other tha

【BZOJ2839】集合计数 组合数+容斥

[BZOJ2839]集合计数 Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007.(是质数喔~) Input 一行两个整数N,K Output 一行为答案. Sample Input 3 2 Sample Output 6 HINT [样例说明]假设原集合为{A,B,C}则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB

bzoj4767两双手 容斥+组合

4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 684  Solved: 208[Submit][Status][Discuss] Description 老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式.老W下棋时觉得无聊,便 决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让 马从(u,v)移动到(u+Bx,v+By).小W看见老

【BZOJ 4455】 [Zjoi2016]小星星 容斥计数

dalao教导我们,看到计数想容斥……卡常策略:枚举顺序.除去无效状态.(树结构) #include <cstdio> #include <cstring> #include <algorithm> typedef long long LL; const int N=20; LL f[N][N]; int n,m,d[N][N],full; bool yeah[N]; int st[N],cnt; struct V{ int to,next; }c[N<<1

bzoj2839 集合计数(容斥)

2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 883  Solved: 490[Submit][Status][Discuss] Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得 它们的交集的元素个数为K,求取法的方案数,答案模1000000007.(是质数喔~) Input 一行两个整数N,K Output 一行为答案. Sample Inp