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

本文探讨了在特定约束条件下,求解一个涉及异或运算的双层求和问题的方法。通过对4k序列异或性质的观察,提出了一种利用拉格朗日插值的高效算法,将复杂度降低到O(tlog⁡t)。文中详细介绍了如何通过取模运算简化计算过程,并给出了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
∑i=1t∑k=xyf(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,...,ik−2,ik−1,ik1,2,3,...,i^k-2,i^k-1,i^k1,2,3,...,ik2,ik1,ik的异或和
1≤t≤105,1≤x≤y≤10181\le t\le 10^5,1\le x \le y \le 10^{18}1t105,1xy1018,最终结果对109+710^9+7109+7取模

分析:
赛后10min写出来,真是可惜
有一个显然但可能不容易想到的结论是4k,4k+1,4k+2,4k+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)可以通过算iki^kik对4取模的结果快速求出,这里就不细写了。
k=1时结果仅与i有关,f(i,k)的前缀和可以写成类似等差数列的和,可以快速求出
k>1时iki^kik对4取模只会有0,1,30,1,30,1,3的结果,且i为偶数时结果为0,imod  4=1i\mod 4=1imod4=1时结果为1,imod  4=3i\mod 4=3imod4=3时根据k的奇偶结果为1或3。
此时结果为1,3时都很好算,而结果为0时f(i,k)=ikf(i,k)=i^kf(i,k)=ik,这样我们的问题就是快速求出
∑i=2t∑k=1nin\sum^t_{i=2}\sum^{n}_{k=1}i^ni=2tk=1nin
后面是一个等差数列,求和后是一个关于i的(n+1)次多项式,而前面的求和则是将整个式子变成了一个关于t的(n+2)次多项式
注意到t最大不超过10510^5105,因此选择取值点为0,1,2,...,t+20,1,2,...,t+20,1,2,...,t+2的拉格朗日插值求解,复杂度O(tlog⁡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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值