计数原理
计数原理是数学中的重要研究对象之一,包括抽屉原理,加法原理,乘法原理,容斥原理
抽屉原理(鸽巢原理)
把n+1件东西放进n个抽屉里面,一定有一个抽屉里放了两件或两件以上(重复、循环)
把n-1件东西放进n个抽屉里面,至少有一个抽屉是空的
加法原理(分类加法原理)
如果事件A有p种生产方式,B有q种生产方式,则事件(A或B)有(p+q)种生产方式
注意:事件A和事件B产生的方式不重合
乘法原理(分布乘法计数原理)
如果事件A有p种生产方式,B有q种生产方式,则事件(A与B)有(p*q)种生产方式
注意:事件A和事件B必须互相独立
加法原理和乘法原理都可以推广到n个事件使用
容斥原理
DeMorgan(德·摩根定律)定理:
设A、B为全集U的任意两个子集,则, (表示补集)
同样可以推广到n个子集使用
//图片来自百度
容斥原理:设S为有穷集,是n条性质,S中的任一元素x对于这n条元素性质可能符合其中的yi't一条,两条,,,,,n条,也可能都不符合,设表示S中具有性质的元素组成的集合,有限集合A的元素个数记作 |A|.
S中具有性质元素个数为
不具有性质的元素个数为
详解:This is the link
求指定区间内与n互素的数的个数:
给出整数n和r。求区间[1;r]中与n互素的数的个数。
去解决它的逆问题,求不与n互素的数的个数。
考虑n的所有素因子pi(i=1…k)
在[1;r]中有多少数能被pi整除呢?它就是:
然而,如果我们单纯将所有结果相加,会得到错误答案。有些数可能被统计多次(被好几个素因子整除)。所以,我们要运用容斥原理来解决。
我们可以用2^k的算法求出所有的pi组合,然后计算每种组合的pi乘积,通过容斥原理来对结果进行加减处理。
关于此问题的最终实现:
int solve (int n, int r)
{
vector<int> p;
for (int i=2; i*i<=n; ++i)
if (n % i == 0)
{
p.push_back (i);
while (n % i == 0)
n /= i;
}
if (n > 1)
p.push_back (n);
int sum = 0;
for (int msk=1; msk<(1<<p.size()); ++msk)
{
int mult = 1, bits = 0;
for (int i=0; i<(int)p.size(); ++i)
if (msk & (1<<i))
{
++bits;
mult *= p[i];
}
int cur = r / mult;
if (bits % 2 == 1)
sum += cur;
else
sum -= cur;
}
return r - sum;
}