牛客练习赛17 C 操作数(组合数+逆元)
给定长度为n的数组a,定义一次操作为:
1. 算出长度为n的数组s,使得si= (a[1] + a[2] + ... + a[i]) mod 1,000,000,007;
2. 执行a = s;
现在问k次操作以后a长什么样。
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; }