Description

Assuming a finite – radius “ball” which is on an N dimension is cut with a “knife” of N-1 dimension. How many pieces will the “ball” be cut into most?
However, it’s impossible to understand the following statement without any explanation.
Let me illustrate in detail.
When N = 1, the “ball” will degenerate into a line of finite length and the “knife” will degenerate into a point. And obviously, the line will be cut into d+1 pieces with d cutting times.
When N = 2, the “ball” will degenerate into a circle of finite radius and the “knife” will degenerate into a line. Likewise, the circle will be cut into (d^2+d+2)/2 pieces with d cutting times.
When N = 3, the “ball” will degenerate into a ball on a 3-dimension space and the “knife” will degenerate into a plane.
When N = 4, the “ball” will degenerate into a ball on a 4-dimension space and the “knife” will degenerate into a cube on a 3 dimension.
And so on.
So the problem is asked once again: Assuming a finite-radius “ball” which is on an N dimension is cut with a “knife” of N-1 dimension. How many “pieces” will the “ball” be cut into most?

Input

The first line of the input gives the number of test cases T. T test cases follow. T is about 300.
For each test case, there will be one line, which contains two integers N, d(1 <= N <= 10^5, 1 <= d <= 10^6).

Output

For each test case, output one line containing “Case #x: y”, where x is the test case number (standing from 1) and y is the maximum number of “pieces” modulo 10^9+7.

Sample Input

3

3 3

3 5

4 5

Sample Output

Case #1: 8

Case #2: 26

Case #3: 31

HINT

Please use %lld when using long long

题目大意就是n维空间切d刀,最多能分成几个部分。

基本上通过推倒三位的大概就能很快推出整个的递推式。

设p(n, d)表示n维空间切d刀。

假设已经切了d-1刀,最后一刀自然切得越多越好。于是最后一刀如果和所有d-1到切的话自然是最好。但是可以逆过来看,相当于d-1到切最后一刀这个n-1维空间。

于是p(n, d) = p(n, d-1) + p(n-1, d-1)

然而这个式子虽然出来了,但是根据n和d的范围打表是不可能的。也不能直接暴力递推求解,自然考虑到可能要直接求表达式。

然而,表达式我求了好久没求出来,不过看了最后表达式后,大概能有以下思路来求通项:

首先有以下事实:

1:手写打表的话:

d->

0

1

2

3

4

5

n

1

1

2

3

4

5

6

2

1

2

4

7

11

16

3

1

2

4

8

15

26

4

1

2

4

8

16

31

5

1

2

4

8

16

32

6

1

2

4

8

16

32

会发现当n >= d时,通项是2^d,其实稍微考虑一下确实如此。因为第一列都是1,自然第二列从第二项开始都是2,同理往后从对角线往后都是乘2,自然是2^d。

2:设p(n, d)的差数列为a(n, d)的话,

自然a(n, d) = p(n, d) – p(n-1, d)

由原式得p(n-1, d) = p(n-1, d-1) + p(n-2, d-1)

三式式消去p得

a(n, d) = a(n, d-1) + a(n-1, d-1)

说明p的差数列也是满足这个递推式,同理p的任意k阶差数列都满足这个式子。

然而让这些差数列最后通项不同的因素自然应该是前几项导致的

有了上面两个结论,于是只用求n < d的情况,可以从下面两个角度考虑

1:利用组合数式子:C(n, m) = C(n-1, m) + C(n-1, m-1),其中C(n, m)表示从n个中取m个。

由于这个式子和题目递推式非常形似。 于是猜测C(n, m)为p的某一阶差数列。根据前几列和前几行的计算,C(n, m)为p的第一阶差数列。于是p(n, d) = sum(C(d, i)) (0 <= i <= n)

2:根据第一个结论:列出第一阶的差数列

d->

0

1

2

3

4

5

n

1

1

2

3

4

5

2

0

0

1

3

6

10

3

0

0

0

1

4

10

4

0

0

0

0

1

5

5

0

0

0

0

0

1

6

0

0

0

0

0

0

基本上可以找规律,发现第一阶差数列是C(n, m)。

然后就是求C(d, i)的和了,由于d很大,考虑C(d, i) = A(d, i) / i!,然后就是求分子和分母在模10^9+7的情况下的商了。自然需要考虑到逆元。

这里对于逆元的处理可以预处理打表,经测试直接在线求exgcd逆元会T掉。

这里预处理用了网上的一个神奇的递推式,还有一种是我大连海事一个同学的做法。

代码(神奇式子):

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#define LL long long
#define N 1000000007 using namespace std; //快速幂
//O(logn)
LL quickPower(LL x, int n)
{
x %= N;
LL a = ;
while (n)
{
a *= n& ? x : ;
a %= N;
n >>= ;
x = (x*x) % N;
}
return a;
} LL c[], a[], inv[];
int n, d; void init()
{
//***预处理所有i在质数MOD下的逆元
inv[] = ;
for (int i = ; i <= ; i++)
inv[i] = inv[N%i]*(N-N/i) % N; a[] = ;
for (int i = ; i <= ; ++i)
a[i] = (inv[i]*a[i-]) % N;
} void work()
{
if (n >= d)
{
printf("%lld\n", quickPower(, d));
return;
}
LL now = d, ans = ;
c[] = ;
for (int i = ; i <= n; ++i)
{
c[i] = (now*c[i-]) % N;
now--;
}
for (int i = ; i <= n; ++i)
{
ans += c[i]*a[i];
ans %= N;
}
printf("%lld\n", ans);
} int main()
{
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
init();
int T;
scanf("%d", &T);
for (int times = ; times <= T; ++times)
{
printf("Case #%d: ", times);
scanf("%d%d", &n, &d);
work();
}
return ;
}

代码二(exgcd):

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define ll long long
#define N 111111
#define D 1111111
#define MOD 1000000007 using namespace std; ll c[N],mu[N];
ll n,d; ll quickpow(ll a,ll n,ll m){
ll ans=;
while(n){
if(n&) ans = (ans*a)%m;
a = (a*a)%m;
n>>=;
}
return ans;
} void ex_gcd(ll a,ll b,ll& d,ll& x,ll& y){
if(!b) {d = a;x = ;y = ;return;}
ex_gcd(b,a%b,d,y,x);
y -= x*(a/b);
} ll inv(ll a,ll n){
ll d,x,y;
ex_gcd(a,n,d,x,y);
return d == ? (x+n)%n : -;
} void init(){
FOR(i,,N){
mu[i] = inv(i,MOD);
}
} void C(){
c[] = ;
FOR(i,,n+){
ll tem = (d+-i)*mu[i]%MOD;
c[i] = (tem*c[i-]) % MOD;
}
} ll solve(){
ll res = ;
FOR(i,,n+){
res += c[i];
res %= MOD;
}
return res;
} int main()
{
//freopen("test.in","r",stdin);
int t,tCase = ;
scanf("%d",&t);
init();
while(t--){
printf("Case #%d: ",++tCase);
scanf("%lld%lld",&n,&d);
ll ans = ;
if(n >= d){
ans = quickpow(,d,MOD);
}
else{
C();
ans = solve();
}
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. install hdp 2.2 on ubuntu 14.04
  2. css 小三角
  3. JS只弹出一个居中弹出窗口
  4. ops中set_sysclk set_clkdiv set_pll详解
  5. Java的文件读写操作 &lt;转&gt;
  6. [Android Pro] ant 编译android工程
  7. Dropbox 有哪些鲜为人知的使用技巧?
  8. JavaScript学习笔记(一)对象和属性
  9. Cat 跨线程之 ForkedTransaction 用法和原理分析
  10. 面向对象 初级版 (Preview) 未完
  11. Git:一、简介&amp;安装Git 2.20.1
  12. [算法竞赛入门经典]Message Decoding,ACM/ICPC World Finals 1991,UVa213
  13. 如何在Asp.Net中使用JQueryEasyUI
  14. Linux 运维工作中的经典应用ansible(批量管理)Docker容器技术(环境的快速搭建)
  15. 835.Hamming距离
  16. [leetcode]58. Length of Last Word最后一个词的长度
  17. kettle学习笔记——插件的安装与使用
  18. TTPRequest 提示#import &lt;libxml/HTMLparser.h&gt;找不到 的解决方法
  19. Mac上使用oh-my-zsh+iterm2
  20. 大数据-图表插件-echarts 样式修改(迭代)

热门文章

  1. Spring学习十三----------Spring AOP的基本概念
  2. myql5.7.7优化配置參数
  3. ubuntu 安装时遇到 hash sum mismatch 处理方法
  4. mnesia的脏写和事物写的测试
  5. linux下压缩成zip文件解压zip文件
  6. 公网yum 源地址
  7. 【BZOJ3291】Alice与能源计划 二分图最大匹配
  8. 连通性 保证f具有介值性质
  9. 【题解】Cut the Sequence(贪心区间覆盖)
  10. 24、Cocos2dx 3.0游戏开发找小三之网格动作:高炫酷的3D动作