牛客练习赛17 C 操作数(组合数+逆元)

给定长度为n的数组a,定义一次操作为:

1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007;
2. 执行a = s;
现在问k次操作以后a长什么样。
输入描述:
第一行两个整数n,k(1 <= n <= 2000, 0 <= k <= 1,000,000,000);
第二行n个整数表示a数组(0 <= ai<= 1,000,000,000)。
输出描述:一行n个整数表示答案。
示例1
输入
3 1
1 2 3
输出
1 3 6
示例2
输入
5 0
3 14 15 92 6
输出
3 14 15 92 6
题意
如上
题解
考虑每次操作完的数都可以由给你的n个数中推出来
a[k][i]=k1*a[1][1]+k2*a[1][2]+k3*a[1][3]+.....+ki*a[1][i]
通过打表找规律可以发现,k=5时
a[5][1]=1*a[1][1]
a[5][2]=5*a[1][1]+1*a[1][2]
a[5][3]=15*a[1][1]+5*a[1][2]+1*a[1][3]
a[5][4]=35*a[1][1]+15*a[1][2]+5*a[1][3]+1*a[1][4]
想到组合数
35=C(3,7),15=C(2,6),5=C(1,5),1=C(0,4)
35=C(3,k+2),15=C(2,k+1),5=C(1,k),1=C(0,k-1)
规律就这样找到了
需要注意这里组合数需要取余,并且mod为质数,直接上逆元
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
ll Pow(ll x,ll n)//逆元
{
    ll res=1;
    while(n)
    {
        if(n&1)res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
ll n,k,a[2005],c[2005];
void solve()
{
    ll shang=k;
    ll xia=1;
    c[1]=1;
    for(int i=2;i<=n;i++)//预处理n个组合数
    {
        c[i]=(shang*Pow(xia,mod-2))%mod;
        shang=shang*(k+i-1)%mod;
        xia=xia*i%mod;
    }
    printf("%lld",a[1]%mod);
    for(int i=2;i<=n;i++)
    {
        ll sum=0;
        for(int j=i,l=1;j>=1;j--,l++)
            sum+=a[l]*c[j]%mod;
        printf(" %lld",sum%mod);
    }
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/taozi1115402474/p/8993848.html