题目来源: CodeForces
基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
给出一个数组A,经过一次处理,生成一个数组S,数组S中的每个值相当于数组A的累加,比如:A = {1 3 5 6} => S = {1 4 9 15}。如果对生成的数组S再进行一次累加操作,{1 4 9 15} => {1 5 14 29},现在给出数组A,问进行K次操作后的结果。(每次累加后的结果 mod 10^9 + 7)
Input
第1行,2个数N和K,中间用空格分隔,N表示数组的长度,K表示处理的次数(2 <= n <= 5000, 0 <= k <= 10^9, 0 <= a[i] <= 10^9)
Output
共N行,每行一个数,对应经过K次处理后的结果。每次累加后mod 10^9 + 7。
Input示例
4 2
1
3
5
6
Output示例
1
5
14
29
思路:当然不能枚举,我们只能去观察一下每个数在每位上的最终贡献, 也就是找系数。
然后我发现这个竟然和怕卡三角形有关,是一个斜对角的一列数。
我们先看
a[1]
a
[
1
]
对于每位的贡献,当k为0或者1时,直接特判 处理,
当k为2时,系数为
1,2,3,4,5...
1
,
2
,
3
,
4
,
5...
当k为3时,系数为
1,3,6,,,
1
,
3
,
6
,
,
,
我们显然可以发现这是一个通项公式,其次数显然为 k−1 k − 1 次,这题用拉格朗日差值也做不了,因为k太大,回到帕斯卡三角,我们发现如果要得到下一项,我们只要知道其有边的一项的值,相加就得到下一项了。
如果我们知道了
Cmn
C
n
m
,我们显然能很快的知道
Cm+1n
C
n
m
+
1
:
每次转移的时候要算逆元,是
logn
l
o
g
n
的,当然可以一次性预处理完就只要
O(1)
O
(
1
)
时间来转移了。预处理时间是
O(n)
O
(
n
)
, 那么这题就做完了.
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#define maxx 5005
#define ll long long
#define mod 1000000007
#define INF 0x3f3f3f3f
using namespace std;
int n,k;
int a[maxx];
ll cf[maxx];
ll ans[maxx];
ll P(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)scanf("%d",a+i);
if(k<=1)
{
if(k==1)
for(int i=1;i<=n;i++)
{
a[i]+=a[i-1];
if(a[i]>=mod)a[i]-=mod;
}
for(int i=1;i<=n;i++)
cout<<a[i]<<endl;
}
else
{
k--;
int m=0;
cf[1]=1;
for(int i=2;i<=n;i++)
{
ll temp=cf[i-1]*(k-m)%mod*P(m+1,mod-2)%mod;
cf[i]=cf[i-1]+temp;
if(cf[i]>=mod)cf[i]-=mod;
++k;++m;
}
for(int i=1;i<=n;i++)
{
for(int j=1;i+j<=n+1;j++)
{
ans[i+j-1]=ans[i+j-1]+cf[j]*a[i]%mod;
if(ans[i+j-1]>=mod)ans[i+j-1]-=mod;
}
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<endl;
}
return 0;
}