机智的手机商(容斥基础题)
第一眼看过去,这哪里是容斥原理的题嘛,明明就是考空间力的题嘛
乍一看还是可难的
毕竟就算告诉你具体数值去硬算都要想很久
并且还需要极强的空间力
(硬算解出来的都可以去参加最强大脑)
所以呢
我们要巧解
那么问题来了???
怎么巧解
我们首先以二维空间的题为例
比如我们先给一张图::
PS::背后不一定是正方形,将就看着
然后呢,有一束光::
这么下来的一束
我们可以发现TA穿透了6个方块
其实好像不需要这么多。。。
画完之后
我们可以发现
这束光如果进入盒子
只有有三种可能
- 从盒子的上面的面进入
- 从盒子左侧的面进入
- 从盒子的左上角进入(图不是很特殊,所以在图中未能很好的体现)
其实我们也可以看到
图中的第一个盒子是从左上角进入的
我们把这束光分解一下
分解成向右和向下的
我们可以发现
从左边进入的(向右的)穿过了3个盒子
也就是
从上边进入的(向下的)穿过了4个盒子
也就是
再减去a和b的最大公约数(从左上角进入的)
也就是
所以就是答案了
附张图::
我们由此可以推到三维空间上去::
首先计算从前面进入盒子的光线即
(画不出立体感不要在意o(>﹏<)o)
然后计算从上面进入盒子的光线即
再来计算从右面进入盒子的光线即
再来计算重叠的
从前面和上面之间的棱的进入盒子的光线即
从上面和右面之间的棱的进入盒子的光线即
从前面和右面之间的棱的进入盒子的光线即
减去之后又还要加从顶点上进入的
即
然后就是答案了
为神马呢???
这个光线穿过的所有的方块
只有三种情况
正如上图所示
而在这三种情况中
都有重复算的
正像接下来的三幅图
而最后棱又被多减了一次
所以还要加回来
所以这是一道容斥原理的题
其实用图来表示是这样的::
然后我们就可以上代码了::
#include<cstdio>
#include<iostream>
using namespace std;
inline void read(int &x) {
x=0;
int f=1;
char s=getchar();
while(s<'0'||s>'9') {
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-48;
s=getchar();
}
x*=f;
}
inline void pr(int x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9)
pr(x/10);
putchar(x%10+48);
}//快读快输不解释
int n,a,b,c;
inline int gcd(int x,int y) {
if(x<y)
swap(x,y);
return y==0?x:gcd(y,x%y);
}
inline int lcm(int x,int y) {
return x*y/gcd(x,y);
}//求最大公倍数
int main() {
read(n),read(a),read(b),read(c);
pr(n/a+n/b+n/c-n/lcm(a,b)-n/lcm(a,c)-n/lcm(b,c)+n/lcm(a,lcm(b,c)));//emmm。。。
}
学会这波神奇的操作了吗??
更多作者博客在这里哟
当然你还可以推到n维空间!!!