2019 ICPC Asia Nanchang Regional M. XOR Sum(拉格朗日插值)

题目

给定t(t<=1e5),x,y(1<=x<=y<=1e18),求\sum_{k=1}^{t}\sum_{i=x}^{y}f(i,k),输出和式对1e9+7取模的值

其中f(i,k)=\bigoplus_{x=1}^{i^k}x,为1到i^k异或的值

思路来源

https://www.cnblogs.com/bringlu/p/12578504.html

官方题解

题解

假酒警告:发现了自己原来的板子在拉格朗日差值部分会爆ll

首先,根据异或这个0123异或起来得0,且逢4就异或得0的性质,可得,

f(x) = \begin{cases} x , x \equiv 0 \mod 4\\ 1 , x \equiv 1 \mod 4\\ x+1 , x \equiv 2 \mod 4\\ 0 , x \equiv 3 \mod 4\\ \end{cases}

所以可以化简,把x项放前面,1项放后面,

注意到i^k\ mod\ 4==0\ or\ 2显然与i^k\ mod \ 2 ==0等价,有下式

\sum_{k=1}^t \sum_{i=x}^y f(i,k) = \sum_{k=1}^t \sum_{i=x}^y i^k [i^k \mod 2 =0] + \sum_{k=1}^t \sum_{i=x}^y [i^k \mod 4 = 1 \text{ or } 2]

讨论i^k \ mod\ 4的值,实际上是讨论i\ mod \4的值,搞出后面那项

①i%4==1,次幂模4意义下呈1 1 1 1,全1分布

②i%4==2,呈2 0 0 0分布,第一个是2后面全是0 

③i%4==3,呈3 1 3 1分布,31交替分布

④i%4==0,呈0 0 0 0分布,全0分布

 

然后考虑前面这项,由于要求是偶数,先提一个2出来

\sum_{k=1}^{t}\sum_{i=1}^{y/2}(2*i)^k-\sum_{k=1}^{t}\sum_{i=1}^{(x-1)/2}(2*i)^k

 

形如\sum_{k=1}^{t}\sum_{i=1}^{m}(2*i)^k的式子怎么求,

如果直接暴力对内部和式插值,再对外部枚举k,复杂度是O(t^2)的,不能接受

考虑交换枚举顺序,这样里面是个等比数列,

\sum_{i=1}^{m}\sum_{k=1}^{t}(2*i)^k=\sum_{i=1}^{m}\frac{2*i*(1-(2*i)^t)}{1-2*i}=\sum_{i=1}^{m}\frac{(2*i)^{t+1}-2*i}{2*i-1}

由于f(i)是最高次幂t+1次的多项式,因此和函数S(i)是t+2次的,

先求出S(i)前t+2项,即下标0到t+1的值,代入m对应的插值即可

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e5+10;
int t;
int sum[N],pre[N],suf[N];
int fac[N],finv[N];
ll x,y,res;
int modpow(int x,int n,int p){
	int res=1;
	for(;n;x=1ll*x*x%p,n>>=1)
	if(n&1)res=1ll*res*x%p;
	return res;
}
//已知f[0]到f[mx] 求f[n]
int cal(int *f,int mx,int n){
	if(n<=mx)return f[n];
    int ans=0;
	pre[0]=suf[mx]=1;
	for(int i=1;i<=mx;++i)
	pre[i]=1ll*(n-i+1)%mod*pre[i-1]%mod;
	for(int i=mx;i>=1;--i)
	suf[i-1]=1ll*(n-i)%mod*suf[i]%mod;
	for(int i=0;i<=mx;++i){
		int sg=(mx-i)&1?-1:1;
		ans=ans+1ll*sg*pre[i]%mod*suf[i]%mod*finv[i]%mod*finv[mx-i]%mod*f[i]%mod;
		if(ans>=mod)ans-=mod;
		if(ans<0)ans+=mod;
	}
    return ans;
}
void init(){
	fac[0]=1;
	for(int i=1;i<N;++i)
	fac[i]=1ll*fac[i-1]*i%mod;
	finv[N-1]=modpow(fac[N-1],mod-2,mod);
	for(int i=N-1;i>=1;--i)
	finv[i-1]=1ll*finv[i]*i%mod;
}
ll cal(ll l,ll r,int a){//[l,r]里有多少%4==a
    ll y=(r-a+4)/4,x=(l-1-a+4)/4;//和0对齐 +4是为了统一r<a的情况 找找规律
    return (y-x+mod)%mod;
}
int main(){
    init();
    scanf("%d%lld%lld",&t,&x,&y);
    sum[0]=0;
    for(int i=1;i<=t+1;++i){//t+1次多项式 代入0到t+1次幂 共t+2个值
        sum[i]=(sum[i-1]+(1ll*modpow(2*i,t+1,mod)-2*i+mod)%mod*modpow(2*i-1,mod-2,mod)%mod)%mod;
    }
    res=(cal(sum,t+1,y/2)-cal(sum,t+1,(x-1)/2)+mod)%mod;
    res=(res+t*cal(x,y,1)%mod)%mod;//不管k为何值 i%4==1 都有(i^k)%4==1 呈 1 1 1 1分布
    res=(res+cal(x,y,2)%mod)%mod;//仅有k=1时 i%4==2 有(i^k)%4==2 呈 2 0 0 0 分布
    res=(res+t/2*cal(x,y,3)%mod)%mod;//i%4==3 都有(i^k)%4==1 呈 3 1 3 1分布
    printf("%lld\n",res);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值