洛谷 P1999 高维正方体

首先这是个玄学的题目,很多人想到了杨辉三角,但是我太菜了于是没有想到,用了另一种方法得出了正确的式子,先写下式子好了。

n n n维下 m m m维的数量:

a n s = C n m × 2 n − m ans=C_n^m\times 2^{n-m} ans=Cnm×2nm

推理过程

先来点简单的

我们很难想象出 4 4 4维或 4 4 4维以上世界是什么样的,但我们知道, 2 2 2维可以用 ( x , y ) (x, y) (x,y)坐标表示, 3 3 3维可以用 ( x , y , z ) (x, y, z) (x,y,z)坐标表示,那 n n n维就可以用 n n n个数表示坐标, n n n维体就是由一些坐标构成的图形,那么坐标的数量就是 0 0 0维的数量。

举个例子,二维可以表示 4 4 4个坐标,分别是 ( 0 , 0 ) , ( 0 , 1 ) , ( 1 , 0 ) , ( 1 , 1 ) (0,0),(0,1),(1,0),(1,1) (0,0),(0,1),(1,0),(1,1),三维是 ( 0 , 0 , 0 ) , ( 0 , 0 , 1 ) , ( 0 , 1 , 0 ) , ⋯   , ( 1 , 1 , 0 ) , ( 1 , 1 , 1 ) (0,0,0),(0,0,1),(0,1,0),\cdots,(1,1,0),(1,1,1) (0,0,0),(0,0,1),(0,1,0),,(1,1,0),(1,1,1),四维是 ( 0 , 0 , 0 , 0 ) (0,0,0,0) (0,0,0,0)等,不难发现,每个坐标只有 0 , 1 0,1 0,1两种,很容易想出 n n n维里 0 0 0维的个数,就是 2 n 2^n 2n

开始正文

观察坐标,以 3 3 3维为例,他的 1 1 1维怎么表示呢?很容易想到,如果两个点的坐标中只有一个不相同的数,那么这两个坐标间可以连一条 1 1 1维的线。

二维呢?还是考虑连线,所以想表示一个 2 2 2维怎么做?那就是连接对角线!

一个对角线一定能对应一个且仅一个 2 2 2维图形。对角线两个端点的坐标的性质,是有两个数不同:原因很简单,举个例子,左上到右下,有 2 2 2个不同因素:左右,上下;那么三维可以考虑出就多了个前后,从而推出m维就有m个因素。

那么对于 n n n维图形,从 2 n 2^n 2n个点出发可以寻找像这样可以表示一个 m m m维图形的线段。

于是转化并简化问题:从坐标角度想,你有一个 n n n 0 0 0组成的排列,问有多少含有 n n n个数且有 m m m 1 1 1 n − m n-m nm 0 0 0的排列。

轻松得出

a n s = C n m × 2 n ans=C^m_n\times 2^n ans=Cnm×2n

诶怎么和上面的式子不太一样

然后就产生疑问了, 2 2 2维图形可以右下 − - 左上,左上 − - 右下,右上 − - 左下,左下 − - 右上,同一个二维图形重复计算 4 4 4次!那么我们考虑下, n n n维下的 m m m维会重复计算多少次,考虑 m = 3 m=3 m=3,从整个三维图形的每个点都可以向对应点发射线段,一个三维图形被重复了 2 3 2^3 23次(也就是三维的点的个数次),考虑 2 2 2维,也是从每个点数到对面都有一条线,重复 2 2 2^2 22次,推理出 m m m维时,这个操作将重复 2 m 2^m 2m次,从而得出最终的式子:

a n s = C n m × 2 n − m ans=C_n^m\times 2^{n-m} ans=Cnm×2nm

#include <iostream>
#include <cstdio>
#include <cmath>
typedef long long ll;
ll ans,a,b,inv[10000001];
const ll MOD=1000000007;
using namespace std;
int q_pow(ll a,ll b){
	ll an=1;
	while (b>0){
		if (b&1)an*=a,an%=MOD;
		a*=a;a%=MOD;
		b>>=1;
	}
	return an;
}
int main(){
	cin>>a>>b;
	if(a<b){
        printf("0");
        return 0;    
    }
	ans=q_pow(2,a-b);
	inv[1]=1;
    for(ll i=2;i<=100000;i++){  
		inv[i]=(MOD-(MOD/i))*inv[MOD%i]%MOD;
    }
    for(int i=1;i<=b;i++)
    {
        ans*=(a-i+1);ans%=MOD;
        ans*=inv[i];ans%=MOD;
    }
    printf("%d",ans);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值