2019 南昌區域賽 M. XOR Sum(拉格朗日插值(模板糾正))

在這裏插入圖片描述


很明顯 f(i,k)f(i,k) 是有規律的,因爲連續的數字異或,連續的兩項異或得到一,打表可以發現:
k = 1
在這裏插入圖片描述
k = 2
在這裏插入圖片描述
k = 3
在這裏插入圖片描述
根據 k 的奇偶以及 i % 4 的餘數進行分類討論,當 i % 4 = 2 時,貢獻爲:
f(n)=k=1t2ki=1n2ikf(n)=\displaystyle\sum_{k = 1}^t2^k\sum_{i = 1}^{\lfloor\frac{n}{2}\rfloor}i^k
右邊是一個 k + 1 次多項式,可以拉個朗日插值求解,但直接做複雜度是 t2t^2

考慮更改枚舉項,得到:
f(n)=i=1n2k=1t2kikf(n)=\sum_{i = 1}^{\lfloor\frac{n}{2}\rfloor}\sum_{k = 1}^t2^ki^k
右邊仍然是一個多項式,是一個以 i 爲自變量的 t 次多項式,因此 f(n)f(n) 是一個以 n 爲自變量的 t+1t + 1 次多項式,右邊式子是一個等比數列的求和形式,可以在 O(log)O(\log) 時間求得,f(n)f(n) 的插值可以在 O(tlog)O(t \log ) 時間內求解,其它情況的貢獻都可以在 O(1) 時間內求得。

注意這裏插值的寫法不能預處理 i=1n(xxi)\prod_{i = 1}^n(x-x_i),計算時乘上 xxix-x_i 的逆元來插值,因爲 xx 非常大,xxix - x_i % mod 可能爲0導致計算的結果不正確。


代碼:

#include<iostream>
using namespace std;
typedef long long ll;
#define LL long long
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
ll t,x,y,mx;
ll g[maxn],fac[maxn],ifac[maxn];
ll pre[maxn],suf[maxn];
inline ll add(ll x, ll y) {
  	x += y;
  	if (x >= mod) {
    	x -= mod;
  	}
  	return x;
}

inline ll sub(ll x,ll y) {
  	x -= y;
  	if (x < 0) {
    	x += mod;
  	}
  	return x;
}

inline ll mul(ll x, ll y) {
  	return x * y % mod;
}
ll fpow(ll a,ll b) {
	ll r = 1;
	while (b) {
		if (b & 1) r = mul(r,a);
		a = mul(a,a);
		b >>= 1;
	}
	return r;
}
ll cal(ll g[maxn],ll x) {			//拉格朗日插值計算多項式
	if (x <= mx) return g[x];
	ll tmp = 1,inv,ans = 0; 
	suf[mx + 1] = pre[0] = 1; 
	for (int i = 1; i <= mx; i++) {
		pre[i] = mul(pre[i - 1],(x - i) % mod);
	}
	for (int i = mx; i >= 1; i--) {
		suf[i] = mul(suf[i + 1],(x - i) % mod);
	}
	for (int i = 1; i <= mx; i++) {
		ll res = 1;
		res = mul(res,g[i]);
		res = mul(res,ifac[i - 1]);
		res = mul(res,ifac[mx - i]);
		res = mul(res,pre[i - 1]);
		res = mul(res,suf[i + 1]);
		if ((mx - i) & 1) ans = sub(ans,res);
		else ans = add(ans,res);
	}
	return ans;
}
ll M(ll x,ll y) {
	if (y == 0) return x / 4;
	return (x / 4 + (x % 4 >= y)) % mod;
}
ll solve(ll x) {
	ll ans = 0;
	ans = M(x,1) * (t % mod) % mod;
	ans = (ans + M(x,3) * (t / 2 % mod) % mod) % mod;
	ans = (ans + M(x,2)) % mod;
	ans = (ans + cal(g,x / 2)); 
	return ans;
}
int main() {
	fac[0] = 1;
	for (int i = 1; i <= maxn - 10; i++)
		fac[i] = mul(fac[i - 1],i);
	ifac[maxn - 10] = fpow(fac[maxn - 10],mod - 2);
	for (int i = maxn - 10 - 1; i >= 0; i--)
		ifac[i] = mul(ifac[i + 1],i + 1);
	scanf("%lld%lld%lld",&t,&x,&y);
	mx = t + 10;
	g[0] = 0;
	for (int i = 1; i <= mx; i++) {
		ll res = (2 * i % mod - fpow(2 * i % mod,t + 1) + mod) % mod * fpow((1 - 2 * i % mod + mod) % mod,mod - 2) % mod;
		g[i] = (g[i - 1] + res) % mod;
	}
	printf("%lld\n",(solve(y) - solve(x - 1) + mod) % mod);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章