反演小结

反演小结

有一类问题是这样的,已知\(f(n)=\sum_{某些条件}g(i)\),求\(g(n)\)

一般我们会根据这个式子求出一个新的式子:\(g(n)=\sum_{另一些条件}f(i)\)

我们将满足上面的形式的式子称为反演,反演是一类经典的问题,本文将对与反演有关的问题进行简单的介绍

二项式反演

简介

对于函数\(f(n)\)\(g(n)\),如果满足

\[f(n)=\sum_{i=0}^n\dbinom{n}{i}g(i) \]

那么

\[g(n)=\sum_{i=0}^n (-1)^{n-i}\dbinom{n}{i}f(i) \]

证明的话考虑代入

\[\begin{aligned} f(n)=&\sum_{i=0}^n \dbinom{n}{i}\sum_{j=0}^i(-1)^{i-j}\dbinom{i}{j}f(j) \\ =&\sum_{j=0}^nf(j)\sum_{i=j}^n(-1)^{i-j}\dbinom{i}{j}\dbinom{n}{i} \end{aligned} \]

注意到有\(\dbinom{n}{i} \dbinom{i}{j}=\frac{n!}{i!(n-i)!}*\frac{i!}{j!(i-j)!}=\frac{n!}{(n-i)!}*\frac{1}{j!(i-j)!}=\frac{n!}{j!(n-j)!}*\frac{(n-j)!}{(n-i)!*(i-j)!}=\dbinom{n}{j}\dbinom{n-j}{n-i}=\dbinom{n}{j}\dbinom{n-j}{i-j}\)

于是就有

\[\begin{aligned} f(n)=&\sum_{j=0}^nf(j)\sum_{i=j}^n(-1)^{i-j}\dbinom{n}{j}\dbinom{n-j}{n-i}\\ =&\sum_{j=0}^nf(j)\dbinom{n}{j}\sum_{i=j}^n(-1)^{n-i}\dbinom{n-j}{n-i}\\ =&\sum_{j=0}^nf(j)\dbinom{n}{j}(1-1)^{n-j}\\ =&\sum_{j=0}^nf(j)[n=j]\\ =&f(n) \end{aligned} \]

类似于莫比乌斯反演(下面会提到),二项式反演也有它的另一种形式,有题目会用到

即已知

\[f(k)=\sum_{i=k}^n\dbinom{i}{k}g(i) \]

那么就有

\[g(k)=\sum_{i=k}^n(-1)^{i-k}\dbinom{i}{k}f(i) \]

证明的话同样考虑代入

\[\begin{aligned} f(k)=&\sum_{i=k}^n\dbinom{i}{k}\sum_{j=i}^n(-1)^{j-i}\dbinom{j}{i}f(j)\\ =&\sum_{j=k}^nf(j)\sum_{i=k}^j(-1)^{j-i}\dbinom{j}{i}\dbinom{i}{k}\\ =&\sum_{j=k}^nf(j)\sum_{i=k}^j(-1)^{j-i}\dbinom{j}{k}\dbinom{j-k}{j-i}\\ =&\sum_{j=k}^nf(j)\dbinom{j}{k}\sum_{i=k}^j(-1)^{j-i}\dbinom{j-k}{j-i}\\ =&\sum_{j=k}^nf(j)\dbinom{j}{k}(1-1)^{j-k}\\ =&\sum_{j=k}^nf(j)\dbinom{j}{k}[j=k]\\ =&f(k) \end{aligned} \]

二项式反演的本质其实就是容斥,关于其从容斥上的证明在此略去

我们来看几道题目

例题

错排问题

题目:给出一个正整数\(n\),求有多少个长为\(n\)的排列\(p\)满足\(p_i\neq i\)

\(f_n\)为长为\(n\)的排列的个数,\(g_i\)表示长为\(n\)的排列中恰有\(i\)个错位的排列个数,那么就有

\[f_n=\sum_{i=0}^n\dbinom{n}{i}g_i=n! \]

反演后可以得到

\[g_n=\sum_{i=0}^n(-1)^{n-i}\dbinom{n}{i}i! \]

直接计算即可

染色问题

题目:有\(1-n\)\(n\)个格子依次排在一排,用\(m\)种染料对它们染色,要求相邻两个格子的颜色不同且每种颜色均出现过至少一次,求方案数

\(f_n\)为使用不超过\(n\)种颜色染色的方案数。\(g_n\)表示恰好使用\(n\)种颜色染色的方案数,答案就是\(g_m\)

\[f_m=\sum_{i=0}^m\dbinom{m}{i}g_i=m*(m-1)^{m-1} \]

反演之后就有

\[g_m=\sum_{i=0}^m(-1)^{m-i}\dbinom{m}{i}f_i \]

直接计算即可

莫比乌斯反演

丢下自己很久以前写下的博客

注意一下莫比乌斯反演不只可以借助\(\mu\)函数进行求解,还可以直接通过计算因数的方法进行求解,这一般适用于需要求\(f_1-f_n\)的值的时候,比如说UOJ #62

z在这里附上vfk的题解(已经讲解的十分详细了):http://vfleaking.blog.uoj.ac/blog/62

以及自己的十分丑陋的代码

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxd=998244353,N=100000;
const double pi=acos(-1.0);
int n,c,d,q;
ll fr[100100],g[100100],b[100100],z[100100];

int read()
{
	int x=0,f=1;char ch=getchar();
	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
	return x*f;
}

ll qpow(ll x,ll y)
{
	ll ans=1,sum=x;
	while (y)
	{
		int tmp=y%2;y/=2;
		if (tmp) ans=(ans*sum)%maxd;
		sum=(sum*sum)%maxd;
	}
	return ans;
}

ll inv(ll x) {return qpow(x,maxd-2);}

void init()
{
	n=read();c=read();d=read();q=read();
	c%=(maxd-1);d%=(maxd-1);
	c-=d;
	c=(c+maxd-1)%(maxd-1);
	int i,j;
	for (i=1;i<=n;i++) fr[i]=qpow(i,c);
	for (i=1;i<=n;i++)
	{
		for (j=i*2;j<=n;j+=i)
		{
			fr[j]=(fr[j]+maxd-fr[i])%maxd;
		}
	}
	//for (i=1;i<=n;i++) cout << fr[i] << " ";cout << endl;
	for (i=1;i<=n;i++) 
	{
		fr[i]=inv(fr[i]);g[i]=inv(qpow(i,d));
	}
	//for (i=1;i<=n;i++) cout << fr[i] << " ";cout << endl;
}

void work()
{
	int i,j;
	for (i=1;i<=n;i++) {b[i]=read();b[i]=(b[i]*g[i])%maxd;}
	for (i=1;i<=n;i++) 
	{
		for (j=i+i;j<=n;j+=i)
		{
			b[j]=(b[j]+maxd-b[i])%maxd;
		}
	}
	for (i=1;i<=n;i++)
	{
		if ((b[i]!=0) && (fr[i]==0)) {printf("-1\n");return;}
		b[i]=(b[i]*fr[i])%maxd;
	}
	for (i=n;i>=1;i--) 
	{
		for (j=i+i;j<=n;j+=i)
		{
			b[i]=(b[i]+maxd-b[j])%maxd;
		}
	}
	for (i=1;i<=n;i++) b[i]=(b[i]*g[i])%maxd;
	for (i=1;i<=n;i++) printf("%lld ",b[i]);printf("\n");
}

int main()
{
	init();
	while (q--) work();
	return 0;
}

单位根反演

简介

单位根是什么?上网搜一篇\(FFT\)的博客,里面一定会提到单位根

或者您可以看这篇:https://www.cnblogs.com/zhou2003/p/10212036.html

注意到之后我们会用到单位根的诸多性质,理解单位根一定不要丢下单位圆

那么单位根反演又是什么呢?其实就是下面这个式子:

\[[n|k]=\frac{1}{n}\sum_{i=0}^{n-1} \omega_n^{ik} \]

证明的话考虑分类讨论,当\(n|k\)

\[\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ik}=\frac{1}{n}\sum_{i=0}^{n-1}1=1 \]

但是当\(n\nmid k\)时,这就是一个简单的等比数列求和求和问题

\[\frac{1}{n}\sum_{i=0}^{n-1}\omega_n^{ik}=\frac{1}{n}*w_n^0\frac{1-w_n^{nk}}{1-w_n^k}=0 \]

利用这个东西我们可以求这样的一个东西:对于序列\(a_1,a_1,\cdots,a_n\),求\(\sum_{k|i}a_i\)

我们考虑序列\(a\)的生成函数\(f(x)\)

由单位根反演我们知道

\[\begin{aligned} \sum_{k|i}a_i&=\frac{1}{k}\sum_{i=1}^{n}a_i\sum_{j=0}^{k-1}w_k^{ij}\\ &=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=1}^na_i\omega_k^{ij}\\ &=\frac{1}{k}\sum_{j=0}^{k-1}f(\omega_k^j) \end{aligned} \]

将单位根带回原多项式求值就是\(FFT\)的前半部分(也就是\(DFT\)),可以在\(O(nlogn)\)的时间内完成

我们将上面这个问题推广一下,给出\(n,k,m\),求\(\sum_{i\text%k=m}a_i\)

比如说现在\(m=1\)

我们来看一下原生成函数的形式:\(f(x)=a_1x+a_2x^2+\cdots+a_nx^n\)

将其除以\(x\)之后得到\(f'(x)=a_1+a_2x+a_3x^2+\cdots+a_nx^{n-1}\)

也就是说我们将在\(f(x)\)代入的单位根在\(f'(x)\)中代入,就可以求出\(\sum_{i\text%k=1}\)的项了

这其实和将代入的单位根除以自己的\(m\)次幂是等价的

于是问题得到了圆满解决

(电脑没电了,明天补例题,就是咕咕了)

posted @ 2019-04-15 21:45  EncodeTalker  阅读(187)  评论(0编辑  收藏  举报