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 ;
}

ACM学习历程—SNNUOJ 1116 A Simple Problem(递推 && 逆元 && 组合数学 && 快速幂)(2015陕西省大学生程序设计竞赛K题)的更多相关文章

  1. ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)

    Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...

  2. ACM学习历程—HDU 5326 Work(树形递推)

    Problem Description It’s an interesting experience to move from ICPC to work, end my college life an ...

  3. ACM学习历程—HDU 5459 Jesus Is Here(递推)(2015沈阳网赛1010题)

    Sample Input 9 5 6 7 8 113 1205 199312 199401 201314 Sample Output Case #1: 5 Case #2: 16 Case #3: 8 ...

  4. AndyQsmart ACM学习历程——ZOJ3872 Beauty of Array(递推)

    Description Edward has an array A with N integers. He defines the beauty of an array as the summatio ...

  5. angry_birds_again_and_again(2014年山东省第五届ACM大学生程序设计竞赛A题)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2877 题目描述 The problems ca ...

  6. ZZUOJ-1195-OS Job Scheduling(郑州大学第七届ACM大学生程序设计竞赛E题)

    1195: OS Job Scheduling Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 106  Solved: 35 [id=1195&quo ...

  7. ACM学习历程—SNNUOJ 1239 Counting Star Time(树状数组 && 动态规划 && 数论)

    http://219.244.176.199/JudgeOnline/problem.php?id=1239 这是这次陕西省赛的G题,题目大意是一个n*n的点阵,点坐标从(1, 1)到(n, n),每 ...

  8. ACM学习历程—HDU 5443 The Water Problem(RMQ)(2015长春网赛1007题)

    Problem Description In Land waterless, water is a very limited resource. People always fight for the ...

  9. 2013年山东省第四届ACM大学生程序设计竞赛J题:Contest Print Server

    题目描述     In ACM/ICPC on-site contests ,3 students share 1 computer,so you can print your source code ...

随机推荐

  1. spring中的事件 applicationevent 讲的确实不错

    event,listener是observer模式一种体现,在spring 3.0.5中,已经可以使用annotation实现event和eventListner里. 我们以spring-webflo ...

  2. VTK学习之路——画画我的小苹果

    数据集主要由描写叙述数据集几何形状的点集数据及构成数据集的单元构成,因此构建数据集的主要任务就是确定点集和构建单元,本演示样例程序构建了一个苹果的实体,然后绘制苹果.演示样例程序运行的过程例如以下: ...

  3. firework压缩图片类似于GD库中压缩图片的思路

    1.先建一张空白图片, 2.再把需要压缩的图片拖上去, 3.符合画布 4.调到需要的大小

  4. 【Android】带底部指示的自定义ViewPager控件

    在项目中经常需要使用轮转广告的效果,在android-v4版本中提供的ViewPager是一个很好的工具,而一般我们使用Viewpager的时候,都会选择在底部有一排指示物指示当前显示的是哪一个pag ...

  5. Epplus 使用案例

    //拷贝 sheet.Cells["6:12"].Copy(sheet.Cells["1:2"]); //边框无 sheet.Cells[(i * 6 + i ...

  6. Android异步处理二:使用AsyncTask异步更新UI界面

    在<Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面>中,我们使用Thread+Handler的方式实现了异步更新UI界面,这一篇中,我们介绍一种更为简 ...

  7. iOS项目 -- 模仿花椒直播做的第一层次界面

    公最近直播比较火爆,我也跟跟风,自己做一个直播app, 现在打算用金山云直播的,但是去注册的时候,联系那边的工作人员,他们讲使用金山云直播要有公司和他们线下签约才能授权开放直播平台. 怎么办呢?于是我 ...

  8. ios 添加全屏返回手势

    1 建立导航控制器 2.导航控制器添加如下代码 - (void)viewDidLoad { [super viewDidLoad]; id target = self.interactivePopGe ...

  9. 3.11 T-SQL语句

    T-SQL语句 1.创建表create table Car     --创建一个名字是Car的表-- ( Code varchar(50) primary key, --第一列名字是Code 数据类型 ...

  10. 九度OJ 1160:放苹果 (DFS)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:998 解决:680 题目描述: 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和 ...