【LOJ 6485】LJJ 学二项式定理(单位根反演)(模板)

LJJ 学二项式定理

题目链接:LOJ 6485

题目大意

求一个式子:
\(\sum\limits_{i=0}^n(\binom{n}{i}s^ia_{i\bmod 4})\)
其中 \(n\leq 10^{18}\)

思路

这道题可以算是单位根反演的模板题。

单位根反演

首先单位根反演是用来处理一下带有取模的式子的。
(就系数里面有取模可以用这个弄掉)

然后式子是 \([n|a]=\dfrac{1}{n}\sum\limits_{k=0}^{n-1}\omega_n^{ak}\)

然后给证明:
\(a\neq 0(\bmod\ n)\)
那我们可以用等比数列求和:
\(\dfrac{1}{n}\dfrac{\omega_n^{an}-1}{\omega_n^a-1}\)
然后 \(\omega^a_n\neq 1,\omega_n^a-1\neq 0\) 分母没问题,分子因为 \(\omega_n^n=\omega_n^0=1\)\(\omega^{an}_n=(\omega_n^n)^a=1,\omega_n^{an}-1=0\)

\(a=0(\bmod\ n)\)
那特殊处理(因为这个时候下面是 \(0\)
\(\dfrac{1}{n}\sum\limits_{k=0}^{n-1}\omega_n^{ak\bmod n}\)
\(\dfrac{1}{n}\sum\limits_{k=0}^{n-1}\omega_n^{0}=\dfrac{1}{n}n=1\)

然后一个经典的式子:
\([a=b\pmod n]=[a-b=0\pmod n]=[n|(a-b)]\)
\(=\dfrac{1}{n}\sum\limits_{k=0}^{n-1}\omega_n^{(a-b)k}=\dfrac{1}{n}\sum\limits_{k=0}^{n-1}\omega_n^{ak}\omega_n^{-bk}\)

这道题

\(\sum\limits_{i=0}^n(\binom{n}{i}s^ia_{i\bmod 4})\)
\(\sum\limits_{i=0}^n(\binom{n}{i}s^i(\sum\limits_{j=0}^3a_j[i\bmod 4=j]))\)
\(\sum\limits_{i=0}^n(\binom{n}{i}s^i(\sum\limits_{j=0}^3a_j[4|i-j]))\)
\(\sum\limits_{i=0}^n(\binom{n}{i}s^i(\sum\limits_{j=0}^3a_j(\dfrac{1}{4}\sum\limits_{k=0}^{3}\omega_4^{ik}\omega_4^{-jk})))\)
\(\dfrac{1}{4}\sum\limits_{k=0}^{3}(\sum\limits_{j=0}^3a_j\omega_4^{-jk})(\sum\limits_{i=0}^n\binom{n}{i}s^i\omega_4^{ik})\)

(二项式反演)
\(\sum\limits_{i=0}^n\binom{n}{i}s^i\omega_4^{ik}\)
\(\sum\limits_{i=0}^n\binom{n}{i}(s\omega_4^{k})^i1^{n-i}\)
\((s\omega_4^k+1)^n\)

(带回原式)
\(\dfrac{1}{4}\sum\limits_{k=0}^{3}(\sum\limits_{j=0}^3a_j\omega_4^{-jk})(s\omega_4^k+1)^n\)

然后 \(\omega_4^1=g^{(mod-1)/4}\)

代码

#include<cstdio>
#define ll long long
#define mo 998244353

using namespace std;

ll n, s, a[4], G = 3, Gv, v4, ans, w[4];

ll ksm(ll x, ll y) {ll re = 1; while (y) {if (y & 1) re = re * x % mo; x = x * x % mo; y >>= 1;} return re;}

int main() {
	int T; scanf("%d", &T); Gv = ksm(G, mo - 2); v4 = ksm(4, mo - 2);
	w[0] = 1; w[1] = ksm(G, (mo - 1) / 4); for (int i = 2; i < 4; i++) w[i] = w[i - 1] * w[1] % mo;
	while (T--) {
		scanf("%lld %lld", &n, &s); for (int i = 0; i < 4; i++) scanf("%lld", &a[i]);
		ans = 0;
		for (int k = 0; k <= 3; k++) {
			ll now = 0;
			for (int j = 0; j <= 3; j++)
				(now += a[j] * w[(4 - j) * k % 4] % mo) %= mo;
			(ans += now * ksm((s * w[k] % mo + 1) % mo, n) % mo) %= mo;
		}
		printf("%lld\n", ans * v4 % mo);
	}
	
	return 0;
} 
posted @ 2022-07-11 15:45  あおいSakura  阅读(36)  评论(0编辑  收藏  举报