单位根反演学习笔记

单位根反演学习笔记

公式

([n|a]=dfrac{1}{n}sumlimits_{k=0}^{n-1}w_n^{ak})

(a=0 pmod n) 时,(w_n^{ak}=1),所以该式的值为 (1)

(a e 0 pmod n) 时,根据等比数列的求和公式,

原式 (=dfrac{1}{n}sumlimits_{k=0}^{n-1}w_n^{ak}=dfrac{1}{n}dfrac{w_n^{an}-1}{w_n^a-1})

分子部分的值为 (0),所以整个式子的值为 (0)

也可以推导出下面的形式:

([a=bpmod n]=[a-b=0pmod n]=dfrac{1}{n}sumlimits_{i=0}^{n-1}w_n^{(a-b)k}=dfrac{1}{n}sumlimits_{i=0}^{n-1}w_n^{ak}w_n^{-bk})

应用

P5591 小猪佩奇学数学

题目描述

给定 (n,p,k),求

[sumlimits_{i=0}^n inom n i imes p^{i} imes leftlfloor dfrac{i}{k} ight floor mod 998244353 ,1 leq n,p <998244353,k in {2^{w}|0 leq w leq 20} ]

分析

(k) 的范围给的很有特点,不难猜出是单位根反演。

发现 (leftlfloor dfrac{i}{k} ight floor =(sum_{j=0}^i[k|j])-1),

带入原式,有

(egin{aligned}sumlimits_{i=0}^n inom n i p^{i} ((sum_{j=0}^i[k|j])-1)&=sumlimits_{i=0}^n inom n i p^{i} ((sum_{j=0}^ifrac{1}{k}sum_{d=0}^{k-1}w_k^{dj})-1)\&= sumlimits_{i=0}^n inom n i p^{i} sum_{j=0}^ifrac{1}{k}sum_{d=0}^{k-1}w_k^{dj}-sum_{i=0}^ninom n ip^i\ &=frac{1}{k}sum_{d=0}^{k-1}sum_{i=0}^ninom n i p^isum_{j=0}^i w_k^{dj}-(p+1)^n\ end{aligned})

后面的部分可以用等比数列求和公式计算,但是要求公比不能为一,所以要特判 (d=0) 的情况。

(egin{aligned}frac{1}{k}sum_{d=0}^{k-1}sum_{i=0}^ninom n i p^isum_{j=0}^i w_k^{dj}-(p+1)^n &=frac{1}{k}sum_{d=1}^{k-1}sum_{i=0}^ninom n i p^ifrac{w_k^{d(i+1)}-1}{w_k^d-1}-(p+1)^n + frac{1}{k}sum_{i=0}^n inom n i p^i (i+1) \ &=frac{1}{k}sum_{d=1}^{k-1}frac{sum_{i=0}^ninom n i p^i(w_k^{d(i+1)}-1)}{w_k^d-1}-(p+1)^n+frac{1}{k}sum_{i=0}^n inom n ip^i i+frac{1}{k}sum_{i=0}^n inom n ip^i \ &=frac{1}{k}sum_{d=1}^{k-1}frac{sum_{i=0}^ninom n i p^iw_k^{d(i+1)}-sum_{i=0}^ninom n i p^i}{w_k^d-1}-(p+1)^n+frac{1}{k}sum_{i=0}^n inom {n-1}{i-1} n p^i+frac{1}{k}(p+1)^n \&=frac{1}{k}sum_{d=1}^{k-1}frac{w_k^dsum_{i=0}^ninom n i (pw_k^d)^i-(p+1)^n}{w_k^d-1}-(p+1)^n+frac{1}{k}np(p+1)^{n-1}+frac{1}{k}(p+1)^n \&=frac{1}{k}sum_{d=1}^{k-1}frac{w_k^d(pw_k^d+1)^n-(p+1)^n}{w_k^d-1}-(p+1)^n+frac{1}{k}np(p+1)^{n-1}+frac{1}{k}(p+1)^n \ end{aligned})

这个东西就可以在 (klogn) 的时间复杂度内计算。

这道题中单位根的带换和二项式定理的使用是很巧妙的。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#define rg register
template<typename T>void read(rg T& x){
	x=0;rg int fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	x*=fh;
}
const int maxn=2e6+5,mod=998244353,G=3;
inline int addmod(rg int now1,rg int now2){
	return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
	return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
	return now1*=now2,now1>=mod?now1%mod:now1;
}
int ksm(rg int ds,rg int zs){
	rg int nans=1;
	while(zs){
		if(zs&1) nans=mulmod(nans,ds);
		ds=mulmod(ds,ds);
		zs>>=1;
	}
	return nans;
}
int n,p,k,ans,wn;
int main(){
	read(n),read(p),read(k);
	wn=ksm(G,(mod-1)/k);
	rg int tmp1,tmp2;
	for(rg int d=1;d<=k-1;d++){
		tmp1=ksm(wn,d);
		tmp2=mulmod(tmp1,ksm(addmod(mulmod(tmp1,p),1),n));
		tmp2=delmod(tmp2,ksm(p+1,n));
		tmp2=mulmod(tmp2,ksm(delmod(tmp1,1),mod-2));
		ans=addmod(ans,tmp2);
	}
	ans=mulmod(ans,ksm(k,mod-2));
	ans=delmod(ans,ksm(p+1,n));
	ans=addmod(ans,mulmod(ksm(k,mod-2),mulmod(n,mulmod(p,ksm(p+1,n-1)))));
	ans=addmod(ans,mulmod(ksm(k,mod-2),ksm(p+1,n)));
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/14590060.html