---待更新---北师大-B:外挂使用拒绝


待更新


链接: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\j1234567n
0x000000
1xxxxxxx
2x2x3x4x5x6x7x
3x3x6x10x15x21x28x
4x4x10x20x35x56x84x
kxk*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时,帐号的金钱数为 Cn1n1+k1x 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]= Cn1n1+k1 C n − 1 + k − 1 n − 1 * init[1] + Cn2n2+k1 C n − 2 + k − 1 n − 2 * init[2] + … + C11+k1 C 1 + k − 1 1 *init[n-1] + C00+k1 C 0 + k − 1 0 *init[n]

因为v[1]=init[1];知道了init[1]的值,可以一步步求解每个帐号的初始值;

二:
还有一点需要注意,即题中给你的并不是每个帐号的实际金钱数,而是对1e9+7取模过的值;
即 v[2] = ( C11+k1 C 1 + k − 1 1 *init[1]+init[2])% mod ;因为init[2] < mod,
所以原式=(( C11+k1 C 1 + k − 1 1 *init[1])) % mod +init[2]) % mod ;
分两种情况:
<1>:(( C11+k1 C 1 + k − 1 1 *init[1])) % mod +init[2])< mod ;
init[2] = v[2] -( C11+k1 C 1 + k − 1 1 *init[1])) % mod ;
<2>:(( C11+k1 C 1 + k − 1 1 *init[1])) % mod +init[2])>= mod ;
init[2] = v[2] + mod -( C11+k1 C 1 + k − 1 1 *init[1])) % mod ;
因为这两种情况只有一个成立,所以两个方程解出来的一定有一个是合法的解。

三:
接下来是组合数取模,需要用到乘法逆元,对于此题可以用 费马小定理 来把除法转化为乘法

Cn1n1+k1 C n − 1 + k − 1 n − 1 %mod = (k1+n1)(k1+n2)(k1+n(n1))(n1)! ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ( n − 1 ) ! % mod

= (k1+n1)(k1+n2)(k1+n(n1))(n1)! ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ( n − 1 ) ! * [(n1)!](mod1) [ ( n − 1 ) ! ] ( m o d − 1 ) % mod

= [(k1+n1)(k1+n2)(k1+n(n1))] [ ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ] * [(n1)!](mod2) [ ( n − 1 ) ! ] ( m o d − 2 ) % mod

= [(k1+n1)(k1+n2)(k1+n(n1))] { [ ( k − 1 + n − 1 ) ∗ ( k − 1 + n − 2 ) ∗ … ∗ ( k − 1 + n − ( n − 1 ) ) ] % mod }*{ [(n1)!](mod2) [ ( 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 ] 表示 [(i1)!](mod2) [ ( i − 1 ) ! ] ( m o d − 2 ) % mod ;

再利用步骤二中的式子求解即可;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值