待更新
链接:https://www.nowcoder.com/acm/contest/117/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
ATG5是ATG系列最新作,游戏故事发生以美国洛杉矶及其周边地区为原型的城市Sos Lantos,是现实地区中的洛杉矶和南加州。制作单位拍摄了超过25万张相关照片,并且研究了人口调查和汽车销售数据,以建立游戏中的世界。
ATG系列历来都是以黑帮生活为背景的知名动作冒险游戏。主人公自然与黑道脱不了干系,在ATG5中游戏元素将会得到增强,加入了更加开放自由的世界,以故事驱动,以任务为准的游戏玩法和多人模式。故事主题聚焦金钱永不眠的南加利福尼亚。这次作品是有史以来最具活力的和最多元化的开放式世界,作为玩家可以反复进入三个角色的生活,玩交织在一起的所有内容。
ATG5这款游戏质量很高,但是外挂猖獗。。。
最近,三七开发现了一款神奇的外挂,可以让他在多个账号之间转移金钱。
神奇外挂的神奇不止于此,当他把一个账号的金钱转移到另一个账户时,原来账户里的金钱并不会减少!是不是很神奇?
三七开一共有n个账号,每一天他都会通过这个神奇外挂把第1个账号的金钱“转移”到第2个账号,再把第2个账号的金钱“转移”到第3个账号,……,再把第n-1个账号的金钱“转移”到第n个账号。
但是三七开忘了一件事情,游戏中金钱数量是有上限的,每当一个账号的金钱数大于等于1000000007(=1e9+7)时,这个账号的金钱数就会对1e9+7取模,即变成金钱数除以1e9+7的余数。尽管如此,三七开还是很开心地继续使用着他的神奇外挂,并且没有花账号里的一分金钱。
然而,在三七开使用了k天神奇外挂之后,B星公司(ATG5的发行公司)发现了他的开挂行为。B星公司对使用外挂行为非常仁慈,决定不对三七开进行封号处理,而是将三七开的所有账号的金钱数恢复至他开挂以前的数值。但服务器并没有关于那么久远的数据的存档,只有现在的金钱数的数据,以及检测到的开挂天数k。
你能帮助B星公司恢复三七开的账号数据吗?
输入描述:
第一行是一个正整数T(T ≤ 15),表示测试数据的组数,
对于每组测试数据,
第一行包含两个整数n(2 ≤ n ≤ 1000),k(0 ≤ k ≤ 100000000),表示账号个数和开挂天数,
第二行包含n个小于1e9+7的非负整数,第i个整数表示当前第i个账号的金钱数。
输出描述:
对于每组测试数据,输出一行,包含n个以空格分隔的非负整数(每个数范围小于109+7,注意不要有行末空格),第i个整数表示开挂前第i个账号的金钱数。
示例
输入
2
3 1
3 2 1
4 2
1 2 1 2
输出
3 1000000006 1000000006
1 0 1000000005 2
解题思路:
一:
dp数组表示之前未使用外挂之前的每个帐号的金钱数
假设第一个账号金钱数为x,其他都为0;
则得到下图:表示在第i天第j个帐号的金钱数
i\j | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … | n |
---|---|---|---|---|---|---|---|---|---|
0 | x | 0 | 0 | 0 | 0 | 0 | 0 | … | |
1 | x | x | x | x | x | x | x | … | |
2 | x | 2x | 3x | 4x | 5x | 6x | 7x | … | |
3 | x | 3x | 6x | 10x | 15x | 21x | 28x | … | |
4 | x | 4x | 10x | 20x | 35x | 56x | 84x | … | |
… | … | … | … | … | … | … | … | … | |
k | x | k*x | [(k+1)*k/2]x | [(k+2)*(k+1)*k/6]x | … | … | … | … | [(k+n-2)(k+n-1)*…*k/(n-1)!]x |
由图可知,第一个帐号的金钱数x不变,而其他的由(本金)和(左边帐号的值)组成,即dp[ i ][ j ]=dp[ i -1 ][ j ]+dp[ i ][ j - 1 ];观察当i==k(即第k天)时帐号的金钱,可得出当j==n时,帐号的金钱数为
Cn−1n−1+k−1∗x
C
n
−
1
+
k
−
1
n
−
1
∗
x
。这是当第一天第一个帐号金钱数为x,而其他帐号均为零的情况,即反映了一个帐号对其后帐号金钱数的影响。
设每个帐号初始值为init[ i ],即
v[1] 不变
v[2]=init[1]的影响+init[2]
v[3]=init[1]的影响+init[2]的影响+init[3]
v[4]=init[1]的影响+init[2]的影响+init[ 3 ]的影响+init[4]
······
v[n]=init[1]的影响+init[2]的影响+······+init[n-1]的影响+init[n]
公式化即
v[n]=
Cn−1n−1+k−1
C
n
−
1
+
k
−
1
n
−
1
* init[1] +
Cn−2n−2+k−1
C
n
−
2
+
k
−
1
n
−
2
* init[2] + … +
C11+k−1
C
1
+
k
−
1
1
*init[n-1] +
C00+k−1
C
0
+
k
−
1
0
*init[n]
因为v[1]=init[1];知道了init[1]的值,可以一步步求解每个帐号的初始值;
二:
还有一点需要注意,即题中给你的并不是每个帐号的实际金钱数,而是对1e9+7取模过的值;
即 v[2] = (
C11+k−1
C
1
+
k
−
1
1
*init[1]+init[2])% mod ;因为init[2] < mod,
所以原式=((
C11+k−1
C
1
+
k
−
1
1
*init[1])) % mod +init[2]) % mod ;
分两种情况:
<1>:((
C11+k−1
C
1
+
k
−
1
1
*init[1])) % mod +init[2])< mod ;
init[2] = v[2] -(
C11+k−1
C
1
+
k
−
1
1
*init[1])) % mod ;
<2>:((
C11+k−1
C
1
+
k
−
1
1
*init[1])) % mod +init[2])>= mod ;
init[2] = v[2] + mod -(
C11+k−1
C
1
+
k
−
1
1
*init[1])) % mod ;
因为这两种情况只有一个成立,所以两个方程解出来的一定有一个是合法的解。
三:
接下来是组合数取模,需要用到乘法逆元,对于此题可以用 费马小定理 来把除法转化为乘法
Cn−1n−1+k−1 C n − 1 + k − 1 n − 1 %mod = (k−1+n−1)∗(k−1+n−2)∗…∗(k−1+n−(n−1))(n−1)! ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ( n − 1 ) ! % mod
= (k−1+n−1)∗(k−1+n−2)∗…∗(k−1+n−(n−1))(n−1)! ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ( n − 1 ) ! * [(n−1)!](mod−1) [ ( n − 1 ) ! ] ( m o d − 1 ) % mod
= [(k−1+n−1)∗(k−1+n−2)∗…∗(k−1+n−(n−1))] [ ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ] * [(n−1)!](mod−2) [ ( n − 1 ) ! ] ( m o d − 2 ) % mod
= {[(k−1+n−1)∗(k−1+n−2)∗…∗(k−1+n−(n−1))] { [ ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ] % mod }*{ [(n−1)!](mod−2) [ ( n − 1 ) ! ] ( m o d − 2 ) % mod }
式子的前半部分直接求,后半部分可以用快速幂,因为值都要使用多次,可以算一遍存在数组里;即两个数组:
<1> kn[ i ] 表示 (k-1+i-1) * (k-1+i-2) * … *(k-1+1) % mod ;
<2> nn[ i ] 表示
[(i−1)!](mod−2)
[
(
i
−
1
)
!
]
(
m
o
d
−
2
)
% mod ;
再利用步骤二中的式子求解即可;