【JoyOI 1858】xlkxc

传送门


problem

给定 k , a , n , d k,a,n,d k,a,n,d,定义 f ( n ) = ∑ i = 1 n i k f(n)=\sum_{i=1}^ni^k f(n)=i=1nik g ( n ) = ∑ i = 1 n f ( i ) g(n)=\sum_{i=1}^nf(i) g(n)=i=1nf(i),求:

h ( n ) = ∑ t = 0 n g ( a + t d ) h(n)=\sum_{t=0}^ng(a+td) h(n)=t=0ng(a+td)

答案对 1234567891 1234567891 1234567891 取模。

数据范围: 1 ≤ k ≤ 123 1\le k\le123 1k123 0 ≤ a , n , d ≤ 123456789 0\le a,n,d\le123456789 0a,n,d123456789


solution

  • f ( n ) f(n) f(n) 是一个自然数幂和,是 ( k + 1 ) (k+1) (k+1) 次多项式。
  • g ( n ) g(n) g(n) f ( n ) f(n) f(n) 的前缀和,是 ( k + 2 ) (k+2) (k+2) 次多项式。
  • h ( n ) h(n) h(n) 貌似有点不好算次数。

我们可以用差分,若对一个多项式差分 k k k 次得到 0 0 0,那么它是 ( k − 1 ) (k-1) (k1) 次多项式。差分得到 h h h ( k + 4 ) (k+4) (k+4) 次的。

所以直接用拉格朗日插出 g g g,再根据 g g g 插出 h h h 即可。

tip:其实只需要知道大致的次数即可。如果实在不能确定准确次数,可以多取几个点算,比如取 ( k + 10 ) (k+10) (k+10) 个点。


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 155
#define P 1234567891
#define ll long long
using namespace std;
int k,a,n,d,up=130,f[N],g[N],h[N],inv[N],ifac[N];
int add(int x,int y)  {return (ll)x+y>=P?(ll)x+y-P:x+y;}
int dec(int x,int y)  {return (ll)x-y< 0?(ll)x-y+P:x-y;}
int mul(int x,int y)  {return (ll)x*y%P;}
int power(int a,int b,int ans=1){
	for(;b;b>>=1,a=mul(a,a))
		if(b&1)  ans=mul(ans,a);
	return ans;
}
void prework(){
	inv[1]=1,ifac[0]=ifac[1]=1;
	for(int i=2;i<=up;++i)  inv[i]=mul(P-P/i,inv[P-P/i*i]);
	for(int i=2;i<=up;++i)  ifac[i]=mul(ifac[i-1],inv[i]);
}
int lagrange(int *a,int x){
	if(x<=up)  return a[x];
	int ans=0;
	for(int i=1;i<=up;++i){
		int temp=mul(a[i],power(x-i,P-2));
		temp=mul(temp,mul(ifac[i-1],(up-i)&1?(P-ifac[up-i]):ifac[up-i]));
		ans=add(ans,temp);
	}
	for(int i=1;i<=up;++i)  ans=mul(ans,x-i);
	return ans;
}
int main(){
	int T;
	scanf("%d",&T);
	prework();
	while(T--){
		scanf("%d%d%d%d",&k,&a,&n,&d);
		for(int i=1;i<=up;++i)  f[i]=add(f[i-1],power(i,k));
		for(int i=1;i<=up;++i)  g[i]=add(g[i-1],f[i]);
		h[0]=lagrange(g,a);
		for(int i=1;i<=up;++i)  h[i]=add(h[i-1],lagrange(g,add(a,mul(i,d))));
		printf("%d\n",lagrange(h,n));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值