BZOJ 1197 花仙子的魔法

版权声明:欢迎转载,但请标注来源 https://blog.csdn.net/qq_42686721/article/details/83066748

Description

相传,在天地初成的远古时代,世界上只有一种叫做“元”的花。接下来,出 现了一位拥有魔法的花仙子,她能给花附加属性,从此,“元”便不断变异,产生了大千世界千奇百怪的各种各样的花。据说,花仙子既可存在于二维空间(平 面),又可存在于三维空间(立体),还可存在于n维空间(想象)。二维空间的点可用向量(x1,x2)表示,三维空间的点可用向量(x1,x2,x3)表 示,一般来说,n维空间的点可用向量(x1,x2,…,xn)表示。而n维空间中两点(x1,x2,…,xn)与(w1,w2,…,wn)之间的距离定义为

在n维空间中,花仙子每实施魔法就要选择一个参考点(w1,w2,…,wn)和一个作用半径r,并且参考点的位置和作用半径的大小可以任意选择。这时,n 维空间中所有与参考点(w1,w2,…,wn)之间的距离小于作用半径r的花都会受到这次魔法的影响。每次魔法都会给受到影响的花带来不同的属性,且的效 果可以叠加。一般来说,若花仙子总共实施了m次魔法,则n维空间中处于某点的花所具有的属性可用长度为m的二进制串a1a2…am来描述,其中对 1≤i≤m,若该花受到第i次魔法的影响,则ai的值为1,否则为0。显然,不同的属性对应不同的花。 现在的问题是:花仙子在n维空间中实施了m次魔法后,最多能得到多少种不同的花?


Input

包含两个整数,并用一个空格隔开,
第一个整数表示实施魔法的次数m,第二个整数表示空间的维数n。
其中,1≤m≤100,1≤n≤15。

Output

仅包含一个整数,表示花仙子在n维空间中实施了m次魔法后,最多能得到多少种不同的花。


Sample Input

3 1

Sample Output

6


题解

(这真的是普及组难度么?我太菜了……)
顺便,请认真读到底,因为算法突破点是在2维部分的讲解!!!算法突破点是在2维部分的讲解!!!算法突破点是在2维部分的讲解!!!

这题代码很好写,但是想出来有难度,可能和空间思维有一定关系吧

对于1维,一个1维的圆其实就是一段线段(或一个区间,圆心的一个半径为r的邻域)
在这里插入图片描述
如图,可以想象为二维圆在一维的投影

现有以下结论:每往1维空间中加入一个一维圆……,最多能增加两种花

问题可以看成,往一维空间中添加线段,然后看线段可以把一维空间分成多少段,注意,一维空间中的两端都是“元”花,即都为同一种

扫描二维码关注公众号,回复: 3753123 查看本文章

证明:
在这里插入图片描述
假设图中的红色线段为新加入的圆,那么只有当左侧红线处于某个已经分隔出来的线段内(比如图中蓝黑线段中间),才能将这个空间分成两个子空间(即多分出来一个空间,如图中的C),另一侧线段可以在除了之前已经被分隔的空间之外的任何空间,可以保证划分出一个新的空间

也就是新增两个子空间
在这里插入图片描述
原谅我的美术……
或者这样:
在这里插入图片描述

所以,一维的时候,我们每增加一个圆,则花的总是最多增加2
即f(1,m) = 2m( f(1,m) 为 1 维空间中添加m个圆最多能形成花的总数)

有了1维的基础,再看看2维会很简单!!

在这里插入图片描述

一开始没有任何圆加入,世界里就只有“元”,这里灰色表示

然后加入了一个圆,
在这里插入图片描述
现在有两种花了……

再加入一个:
在这里插入图片描述
现在有四种花了,不过为什么?
重点来了!

我们把加入的第二个圆,从某个点拆开,变成线段
在这里插入图片描述
再看看两个交点,我们彻底把线段铺平:
在这里插入图片描述
好像就变成了一维的情况,增加的区域数也正好等于在1为空间中加入一个圆后得到花的总数
我们再添加第三个球也是如此:
在这里插入图片描述
把第三个圆的线段拉平,又变成一维了
而且多划分出的区域为4 = 一维中加入两个圆后得到花的总数

3维,n维同理

那么应该可以得出了吧……
f [ a ] [ b ] f[a][b] 表示a维空间中加入b个a维球体后花的总数(划分的空间数)
f [ a ] [ b ] = f [ a ] [ b 1 ] + f [ a 1 ] [ b 1 ] f[a][b] = f[a][b-1] + f[a-1][b-1]
后面 + f [ a 1 ] [ b 1 ] + f[a-1][b-1] 的原因图中已经可以看到,n维球相交可以转换为n-1维球相交的问题
而再加一个 f [ a ] [ b 1 ] f[a][b-1] ,因为我们在加入b-1个球的基础上再加入第b个球,所以……

code

#include <cstdio>

long long f[20][110];
int m, n;
int main() {
	int i, j;
	scanf ("%d%d", &m, &n);
	f[0][0] = 1;
	for (j = 1; j <= m; ++ j) f[0][j] = 2;
	for (i = 1; i <= n; ++ i) {
		f[i][0] = 1;
		for(j = 1; j <= m; ++ j) f[i][j] = f[i][j - 1] + f[i - 1][j - 1];
	}
	printf ("%d\n", f[n][m]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42686721/article/details/83066748
今日推荐