ACM学习历程—SNNUOJ 1116 A Simple Problem(递推 && 逆元 && 组合数学 && 快速幂)(2015陕西省大学生程序设计竞赛K题)
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题)的更多相关文章
- ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)
Description Byteland国家的网络单向传输系统可以被看成是以首都 Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的 ...
- ACM学习历程—HDU 5326 Work(树形递推)
Problem Description It’s an interesting experience to move from ICPC to work, end my college life an ...
- 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 ...
- 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 ...
- angry_birds_again_and_again(2014年山东省第五届ACM大学生程序设计竞赛A题)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2877 题目描述 The problems ca ...
- 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 ...
- ACM学习历程—SNNUOJ 1239 Counting Star Time(树状数组 && 动态规划 && 数论)
http://219.244.176.199/JudgeOnline/problem.php?id=1239 这是这次陕西省赛的G题,题目大意是一个n*n的点阵,点坐标从(1, 1)到(n, n),每 ...
- 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 ...
- 2013年山东省第四届ACM大学生程序设计竞赛J题:Contest Print Server
题目描述 In ACM/ICPC on-site contests ,3 students share 1 computer,so you can print your source code ...
随机推荐
- php开启pathinfo 模式
pathinfo 模式 需要 php.ini 开启下面这个参数 cgi.fix_pathinfo=1 path_info模式:http://www.xxx.com/index.php/模块/方法 ...
- Linux下实现RAID
一.实验目的 1.掌握Linux系统下软RAID的实现方法: 2.掌握RAID5的配置过程: 3. 通过实验熟悉RAID.5的特点. 二.实验内容及步骤 1.在VMware中创建一台Linux. 2. ...
- redis写磁盘报错Cannot allocate memory
查看 Redis 日志发现系统在频繁报错: [1821] 10 Nov 09:59:04.086 # Can't save in background: fork: Cannot allocate m ...
- Mongodb亿级数据量的性能测试
进行了一下Mongodb亿级数据量的性能测试,分别测试如下几个项目: (所有插入都是单线程进行,所有读取都是多线程进行) 1) 普通插入性能 (插入的数据每条大约在1KB左右) 2) 批量插入性能 ...
- Javascript文件加载:LABjs和RequireJS
传统上,加载Javascript文件都是使用<script>标签. 就像下面这样: <script type="text/javascript" src=&quo ...
- EasyNVR RTSP转HLS(m3u8+ts)流媒体服务器前端构建之:bootstrap-datepicker日历插件的实时动态展现
EasyNVR中有对录像进行检索回放的功能,且先抛开录像的回放,为了更好的用户体验过.让用户方便快捷的找到对应通道对应日期的录像视频,是必须的功能. 基于上述的需求,为前端添加一个日历插件,在日历上展 ...
- c++中的重载、覆盖和隐藏
1 重载发生在同一个类内部. 同一个类内部,具有相同的函数名,但是参数列表不同,那么就是重载.因为c++编译器编译时,将函数名和函数列表一起对函数进行了重命名. 2 覆盖和隐藏发生在子类和父类之间. ...
- 题解 P3805 【【模板】manacher算法】
题解 P3805 [[模板]manacher算法] 我们先看两个字符串: ABCCBA ABCDCBA 显然这两字符串是回文的 然而两个串的对称中心的特性不同,第一个串,它的对称中心在两个C中间,然而 ...
- GStreamer 从摄像头获取图像 转264
1.这里有个简单的例子,可以看看GStreamer如何编程的. 2.GStreamer GstAppSink的官方Document,翻译了一下它的描述部分,点击这里. 3.GStreamer Gs ...
- rails debug
=debug @thesis config下配置 东西需要重启之后才管用