题意:
求 ∑ i = 1 t ∑ k = x y f ( i , k ) \sum^t_{i=1}\sum^y_{k=x}f(i,k) i=1∑tk=x∑yf(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,...,ik−2,ik−1,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} 1≤t≤105,1≤x≤y≤1018,最终结果对 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(k∈Z)的异或和为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=2∑tk=1∑nin
后面是一个等差数列,求和后是一个关于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
#include
#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);
}