2019 ACM/ICPC 南昌站 G,拉格朗日插值

题意:
∑ i = 1 t ∑ k = x y f ( i , k ) \sum^t_{i=1}\sum^y_{k=x}f(i,k) i=1tk=xyf(i,k)
其中 f ( i , k ) f(i,k) f(i,k)表示 1 , 2 , 3 , . . . , i k − 2 , i k − 1 , i k 1,2,3,...,i^k-2,i^k-1,i^k 1,2,3,...,ik2,ik1,ik的异或和
1 ≤ t ≤ 1 0 5 , 1 ≤ x ≤ y ≤ 1 0 18 1\le t\le 10^5,1\le x \le y \le 10^{18} 1t105,1xy1018,最终结果对 1 0 9 + 7 10^9+7 109+7取模

分析:
赛后10min写出来,真是可惜
有一个显然但可能不容易想到的结论是 4 k , 4 k + 1 , 4 k + 2 , 4 k + 3 ( k ∈ Z ) 4k,4k+1,4k+2,4k+3(k\in Z) 4k,4k+1,4k+2,4k+3(kZ)的异或和为0,因此f(i,k)可以通过算 i k i^k ik对4取模的结果快速求出,这里就不细写了。
k=1时结果仅与i有关,f(i,k)的前缀和可以写成类似等差数列的和,可以快速求出
k>1时 i k i^k ik对4取模只会有 0 , 1 , 3 0,1,3 0,1,3的结果,且i为偶数时结果为0, i m o d    4 = 1 i\mod 4=1 imod4=1时结果为1, i m o d    4 = 3 i\mod 4=3 imod4=3时根据k的奇偶结果为1或3。
此时结果为1,3时都很好算,而结果为0时 f ( i , k ) = i k f(i,k)=i^k f(i,k)=ik,这样我们的问题就是快速求出
∑ i = 2 t ∑ k = 1 n i n \sum^t_{i=2}\sum^{n}_{k=1}i^n i=2tk=1nin
后面是一个等差数列,求和后是一个关于i的(n+1)次多项式,而前面的求和则是将整个式子变成了一个关于t的(n+2)次多项式
注意到t最大不超过 1 0 5 10^5 105,因此选择取值点为 0 , 1 , 2 , . . . , t + 2 0,1,2,...,t+2 0,1,2,...,t+2的拉格朗日插值求解,复杂度 O ( t log ⁡ t ) O(t \log t) O(tlogt)

代码:

#include<cstdio>
#include<iostream>
#define mo 1000000007
#define LL long long 
using namespace std;
int t;
LL L,R,y[100050],fac[100050],inv[100050],pre[100050],sub[100050];
int qr(int x,int y)
{
	int t=1;
	for (;y;y>>=1,x=1LL*x*x%mo)
		if (y&1) t=1LL*t*x%mo;
	return t;
}
LL cha(LL x,int n)
{
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for (int i=2;i<=n;++i) fac[i]=fac[i-1]*i%mo,inv[i]=inv[mo%i]*(mo-mo/i)%mo;
	for (int i=2;i<=n;++i) inv[i]=inv[i]*inv[i-1]%mo;
	LL yy=0;
	y[0]=0;
	for (int i=1;i<=n;++i)
	{
		yy+=(2LL*i)%mo*(2LL*i)%mo*qr(2*i-1,mo-2)%mo*(qr(2*i,t-1)-1)%mo;
		yy%=mo;
		y[i]=yy;
	}
	LL ans=0,prod;
	pre[0]=x%mo;
	for (int i=1;i<=n;++i) pre[i]=pre[i-1]*((x-i)%mo)%mo;
	sub[n]=(x-n)%mo;
	for (int i=n-1;i>=0;--i) sub[i]=sub[i+1]*((x-i)%mo)%mo;
	for (int i=0;i<=n;++i)
	{
		prod=y[i];
		if (i) prod=prod*inv[i]%mo*pre[i-1]%mo;
		if (i<n) prod=prod*inv[n-i]%mo*sub[i+1]%mo;
		if (n-i&1) prod=-prod;
		ans=(ans+prod);
		ans%=mo;
	}
	return ans;
}
LL cal(LL z,int t)
{
	LL ans=0,tmp;
	tmp=(z+1)/4-1;tmp%=mo;
	ans+=tmp*(tmp+1)%mo*4%mo+(tmp+1)*4%mo;
	ans%=mo;
	if (z>=3)ans+=((z-3)/4+1)%mo*(t/2)%mo;
	ans%=mo;
	if (z>=1)ans+=((z-1)/4+1)%mo*(t-1)%mo;
	ans%=mo;
	ans+=cha(z/2,t+3);
	ans%=mo;
	for (LL i=((z+1)/4)*4;i<=z;++i)
		if (i%4==0) ans=(ans+i)%mo;
		else if (i%4==1) ans=(ans+1)%mo;
		else if (i%4==2) ans=(ans+1+i)%mo;
	return ans%mo;
}
main()
{
	scanf("%d%lld%lld",&t,&L,&R);
	printf("%lld\n",((cal(R,t)-cal(L-1,t))%mo+mo)%mo);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值