【51nod 1161】 Partial Sums (组合数学)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Coldfresh/article/details/82497118

题目来源: 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 ] 对于每位的贡献,当k为0或者1时,直接特判 处理,
当k为2时,系数为 1 , 2 , 3 , 4 , 5...
当k为3时,系数为 1 , 3 , 6 , , ,

我们显然可以发现这是一个通项公式,其次数显然为 k 1 次,这题用拉格朗日差值也做不了,因为k太大,回到帕斯卡三角,我们发现如果要得到下一项,我们只要知道其有边的一项的值,相加就得到下一项了。

如果我们知道了 C n m ,我们显然能很快的知道 C n m + 1

C n m + 1 = n m m + 1 C n m

每次转移的时候要算逆元,是 l o g n 的,当然可以一次性预处理完就只要 O ( 1 ) 时间来转移了。预处理时间是 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;
}

猜你喜欢

转载自blog.csdn.net/Coldfresh/article/details/82497118
今日推荐