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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章