一些经典的容斥问题

  • 在平面中给$n$个点,求这$n$个点构成的三角形/锐角三角形的个数。

求三角形的个数比较简单。首先全集是$\binom{n}{3}$,然后考虑补集,补集就是三点共线的点对。所以我们可以枚举每一个点,然后为了避免算重,我们接下来只考虑标号比当前点小的点。接着就进行极角排序,这样就可以统计出当前点所在的所有直线以及直线上的点的个数。设某直线上有$m$个点,那么答案就减去$\binom{m}{3}$即可。注意处理重点的情况。

求锐角三角形的个数也比较简单,只不过补集除了三点共线之外,还会有钝角三角形和直角三角形。然而我们还是可以考虑枚举每一个点$u$,只不过这里不需要只考虑标号比当前点小的点了,因为接下来的算法不会算重。然后也还是极角排序,然后按照极角序枚举另一个点$v$,这样就构成了一条线段$u-v$。然后过点$u$作线段$u-v$的垂线,那么在垂线另一边或者正好在垂线上的点都和$u,v$构成非锐角三角形或直线,统计这样的点的个数即可,利用单调性可以做到$O(n)$求解。然后每个非锐角三角形或直线会被算两次,所以最后再除以2就行了。

至于题目的话,就写个正解写个暴力拍一拍吧。反正你们这么强,分分钟就可以写完。

  • 给一个环,环上有$n$个点。现在你有$m$种颜色,然后你要给每个点染一种颜色,并使得最后所有相邻的点的颜色都不相同,问有多少种染色方案。

首先考虑全集,就是$m\times (m-1)^{n-1}$。意思就是第一个点任选颜色,后面的点任选和上个点不同的颜色。听起来很靠谱,但是最后一个就可能和第一个变成一样的颜色。所以我们要减去补集,就是最后一个和第一个颜色相同的情况的种数,即$m\times (m-1)^{n-2}$。然后发现又减多了,把倒数第二个和倒数第一个颜色相同的情况也给减掉了,实际上这是不能减的,所以我们要加回来,即加上$m\times (m-1)^{n-3}$。就这样一直反复,直到最后没有后续状态了为止。所以有:

$$Ans=m\times(m-1)^{n-1}-m\times(m-1)^{n-2}+m\times(m-1)^{n-3}-m\times(m-1)^{n-4}+...+m\times(-1)^{n-1}$$

最后用等比公式求和即可简化计算。

再给一个类似的题吧。http://codeforces.com/gym/100548/attachments F题

  • 给一个$n\times m$的网格,你一开始在$(1,1)$上,然后要走到$(n,m)$,每次可以往右走或者往下走一格,但是不能出界。然而在网格中有$k$个障碍点,你不能走到障碍点上,问有多少种从$(1,1)$走到$(n,m)$的走法。

首先全集就是$\binom{n+m-2}{n-1}$,要走$n+m-2$步,其中有$n-1$步是往下,所以总方案数就是$\binom{n+m-2}{n-1}$。做这类题目的关键因素之一就是能够很快的算出或者预处理出一个子矩阵的全集。然后我们考虑补集,我们考虑只经过了一个障碍点的路径,假设该障碍点是$(u,v)$,那么所有经过该障碍点的路径条数即为$S(u,v)\times S(n-u+1,m-v+1)$,其中$S(x,y)$表示从$(1,1)$走到$(x,y)$的放案数,即$\binom{x+u-2}{x-1}$。然后将其减去。但是我们再来考虑那些经过了两个障碍点的路径,这些路径被减去了两次,所以我们要加回来。然后又要减去经过了三个障碍的,加上经过了四个障碍的......所以我们可以考虑给障碍点之间连边。$(u,v)$给$(p,q)$连边当且仅当$u\le p$且$v\le q$且$u\neq p,v\neq q$。但是在这样的图中链是很多的,所以我们可以考虑动态规划。设$Dp[i][j]$表示从$(1,1)$开始,以$j$结尾的包含了$i$个障碍点的路径条数,转移就枚举$j$的每一个后继$u$,令$Dp[i+1][u]+=Dp[i][j]\times S(x_u-x_j+1,y_u-y_j+1)$,然后$Dp[i][j]$对答案的贡献就是$Dp[i][j]\times S(n-x_j+1,m-y_j+1)\times (-1)^i$,累加贡献即可。复杂度是$O(Calc_S\times k^3)$的,其中$Calc_S$是计算$S$的时间复杂度。

给一个类似的题:http://acm.hdu.edu.cn/showproblem.php?pid=5794

我把我的代码贴上来吧,仅供参考。

  1 #include <map>
  2 #include <ctime>
  3 #include <cstdio>
  4 #include <vector>
  5 #include <algorithm>
  6 using namespace std;
  7 typedef long long LL;
  8 #define N 100 + 5
  9 #define Mod 110119
 10
 11 int Case, r, ans, Fac[Mod], Inv[Mod], Ord[N], TMP[N][N], W[N][N];
 12 bool Ok[N], Inq[N];
 13 LL n, m, X[N], Y[N], _X[N], _Y[N];
 14 vector <int> To[N], Vec[N];
 15
 16 inline int Inc(int a, int b)
 17 {
 18     return a + b - (a + b >= Mod ? Mod : 0);
 19 }
 20
 21 inline bool cmp(int u, int v)
 22 {
 23     return make_pair(X[u], Y[u]) < make_pair(X[v], Y[v]);
 24 }
 25
 26 inline int Power(int u, int v)
 27 {
 28     int res = 1;
 29     for (; v; v >>= 1)
 30     {
 31         if (v & 1) res = (LL) res * u % Mod;
 32         u = (LL) u * u % Mod;
 33     }
 34     return res;
 35 }
 36
 37 inline void Prepare()
 38 {
 39     Fac[0] = Inv[0] = 1;
 40     for (int i = 1; i < Mod; i ++)
 41         Fac[i] = (LL) Fac[i - 1] * i % Mod;
 42     Inv[Mod - 1] = Power(Fac[Mod - 1], Mod - 2);
 43     for (int i = Mod - 2; i; i --)
 44         Inv[i] = (LL) Inv[i + 1] * (i + 1) % Mod;
 45 }
 46
 47 inline int C(int x, int y)
 48 {
 49     if (x < y) return 0;
 50     return (LL) Fac[x] * Inv[y] % Mod * Inv[x - y] % Mod;
 51 }
 52
 53 inline int Com(LL x, LL y)
 54 {
 55     if (x < y || x < 0 || y < 0) return 0;
 56     if (y == 0) return 1;
 57     if (x < Mod && y < Mod) return C(x, y);
 58     return (LL) C(x % Mod, y % Mod) * Com(x / Mod, y / Mod) % Mod;
 59 }
 60
 61 inline int Get(LL u, LL v)
 62 {
 63     if ((u + v - 2) % 3 != 0) return 0;
 64     LL t = (u + v - 2) / 3;
 65     LL x = u - 1 - t, y = v - 1 - t;
 66     int res = Com(x + y, x);
 67     return res;
 68 }
 69
 70 inline int Get_1(int u, int v)
 71 {
 72     if (TMP[u][v] != -1) return TMP[u][v];
 73     return TMP[u][v] = Get(X[v] - X[u] + 1, Y[v] - Y[u] + 1);
 74 }
 75
 76 inline void Handle()
 77 {
 78     ans = Get_1(0, r + 1);
 79     for (int i = 1; i <= r; i ++)
 80     {
 81         if (!Ok[i]) continue ;
 82         Vec[1].push_back(i);
 83         W[1][i] = Get_1(0, i);
 84     }
 85     for (int k = 1; k <= r; k ++)
 86     {
 87         for (int i = 1; i <= r; i ++) Inq[i] = 0;
 88         for (int i = 0; i < Vec[k].size(); i ++)
 89         {
 90             int j = Vec[k][i];
 91             int tmp = (LL) W[k][j] * Get_1(j, r + 1) % Mod;
 92             if (k & 1) tmp = Mod - tmp;
 93             ans = Inc(ans, tmp);
 94             for (int l = 0; l < To[j].size(); l ++)
 95             {
 96                 int d = To[j][l];
 97                 if (!Ok[d]) continue ;
 98                 if (!Inq[d]) Vec[k + 1].push_back(d), Inq[d] = 1;
 99                 W[k + 1][d] = Inc(W[k + 1][d], (LL) W[k][j] * Get_1(j, d) % Mod);
100             }
101         }
102     }
103 }
104
105 int main()
106 {
107     Prepare();
108     while (scanf("%lld%lld%d", &n, &m, &r) > 0)
109     {
110         X[0] = Y[0] = 1, Ok[0] = 1;
111         bool ok = 1;
112         for (int i = 1; i <= r; i ++)
113         {
114             scanf("%lld%lld", X + i, Y + i);
115             if (X[i] == n && Y[i] == m) ok = 0;
116             Ord[i] = i, Ok[i] = 1;
117         }
118         for (int i = 0; i <= r + 1; i ++)
119             for (int j = 0; j <= r + 1; j ++)
120                 TMP[i][j] = -1, W[i][j] = 0;
121         sort(Ord + 1, Ord + r + 1, cmp);
122         for (int i = 1; i <= r; i ++)
123             _X[i] = X[Ord[i]], _Y[i] = Y[Ord[i]];
124         for (int i = 1; i <= r; i ++)
125         {
126             X[i] = _X[i], Y[i] = _Y[i];
127             if (X[i] == X[i - 1] && Y[i] == Y[i - 1]) Ok[i] = 0;
128         }
129         if (n == 1 && m == 1)
130         {
131             printf("Case #%d: %d\n", ++ Case, 1);
132             continue ;
133         }
134         if (!ok)
135         {
136             printf("Case #%d: %d\n", ++ Case, 0);
137             continue ;
138         }
139         X[r + 1] = n, Y[r + 1] = m, Ok[r + 1] = 1;
140         for (int i = 0; i <= r + 1; i ++)
141             To[i].clear(), Vec[i].clear();
142         for (int i = 1; i < r; i ++)
143             for (int j = i + 1; j <= r; j ++)
144                 if (X[j] > X[i] && Y[j] > Y[i] && Ok[j])
145                     To[i].push_back(j);
146         Handle();
147         printf("Case #%d: %d\n", ++ Case, ans);
148     }
149     return 0;
150 }

HDOJ 5794

时间: 2024-10-12 18:08:29

一些经典的容斥问题的相关文章

XTU 1242 Yada Number 容斥

Yada Number Problem Description: Every positive integer can be expressed by multiplication of prime integers. Duoxida says an integer is a yada number if the total amount of 2,3,5,7,11,13 in its prime factors is even. For instance, 18=2 * 3 * 3 is no

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

容斥 - HDU 4135 Co-prime

Co-prime Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=4135 推荐: 容斥原理 Mean: 给你一个区间[l,r]和一个数n,求[l,r]中有多少个数与n互素. analyse: 经典的容斥原理题. 如果题目是说求1~n中有多少个数与n互质,我们一定反应应该是欧拉函数. 但是如果n特别大或者说是求某个给定区间与n互素的个数,这时用欧拉函数就行不通. 容斥做法:首先我们可以在O(sqrt(n))内求出n的所有质因数p

不容易系列之一(错排公式+容斥)

不容易系列之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 17475    Accepted Submission(s): 7284 Problem Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 做好“一件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比挣钱容

[bzoj3622]已经没有什么好害怕的了——容斥or二项式反演+DP

题目大意: 给定两个长度为\(n\)的序列,求有多少种匹配方式,使得\(a_i<b_i\)的个数恰好为\(k\)个. 思路: 据说是一道二项式反演的经典例题了. 首先如果要求正好等于\(k\)个的是不太好求的,我们可以考虑求出至少为\(k\)个的方案数. 首先先把两个序列都按照从小到大的顺序排好序,然后以序列\(b\)为对象dp. 我们设\(f_{i,j}\)表示前\(i\)个数里面强制确定了\(j\)个\(a_i<b_i\)关系的方案数,记\(c_i\)表示在\(a\)中有多少个数<\

HAOI2018染色——容斥

题目大意 loj 思路 设\(f_i\)表示至少出现了i种颜色的方案数 \[ \begin{aligned} f_i&={m \choose i}\times \frac{(s\times i)!}{(s!)^{i}}\times {n\choose s\times i}\times (m-i)^{n-s\times i}\f_i&={m \choose i}\times \frac{n!}{(s!)^{i}\times (n-s\times i)!}\times (m-i)^{n-s\t

Lucky HDU - 5213 (莫队,容斥)

WLD is always very lucky.His secret is a lucky number . is a fixed odd number. Now he meets a stranger with numbers:.The stranger asks him questions.Each question is like this:Given two ranges and ,you can choose two numbers and to make .The you can

「总结」容斥。三.广义容斥

首先让我们考虑反演的真正原理. $fr.$反演原理 对于两个函数$f$和$g$. 我们知道: $$g(n)=\sum\limits_{i=0}^{n}a_{n,i}f(i)$$ $$f(n)=\sum\limits_{i=0}^{n}b_{n,i}g(i)$$ 将第一个式子代入第二个. $$\begin{array}{rcl}\\f(n)&=&\sum\limits_{i=0}^{n}b_{n,i}\sum\limits_{j=0}^{i}a_{i,j}f(j)\\&=&\

POJ 2773 Happy 2006 二分+容斥(入门

题目链接:点击打开链接 题意: 输入n ,k 求与n互质的第k个数(这个数可能>n) 思路: solve(mid)表示[1,mid]中有多少个和n互质,然后二分一下最小的mid 使得互质个数==k solve(x) 实现: 与n互质的个数=所有数-与n不互质的数=所有数-(与n有一个因子-与n有2个因子的+与n有3个因子的) 状压n的因子个数,然后根据上面的公式容斥得到. #include <stdio.h> #include <iostream> #include <